<?php

namespace App\Controllers\Api;

use CodeIgniter\HTTP\ResponseInterface;

class OnboardController extends BaseApiController
{
    protected $format = 'json';
    protected $table = 'onboard';

    /**
     * 선상 목록
     * GET /api/onboard/list
     */
    public function index()
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        try {
            $page = (int) ($this->request->getGet('page') ?? 1);
            $perPage = (int) ($this->request->getGet('per_page') ?? 10);
            if ($page < 1) $page = 1;
            if ($perPage < 1) $perPage = 10;
            $offset = ($page - 1) * $perPage;

            $searchField = trim((string) $this->request->getGet('search_field')); // '', field, area, name
            $search      = trim((string) $this->request->getGet('search'));
            $partnership = trim((string) $this->request->getGet('partnership'));
            $status      = trim((string) $this->request->getGet('status'));
            $startDate   = trim((string) $this->request->getGet('start_date')); // YYYY-MM-DD
            $endDate     = trim((string) $this->request->getGet('end_date'));   // YYYY-MM-DD
            $fieldId     = (int) ($this->request->getGet('field_id') ?? 0);
            $areaId      = (int) ($this->request->getGet('area_id') ?? 0);

            $db = $this->getDB();
            $builder = $db->table($this->table . ' o');
            $builder->join('fishing_field f', 'f.id = o.field_id', 'left');
            $builder->join('fishing_area a', 'a.id = o.area_id', 'left');
            $builder->where('o.deleted_YN', 'N');

            if ($search !== '') {
                if ($searchField === 'field') {
                    $builder->like('f.name', $search);
                } elseif ($searchField === 'area') {
                    $builder->like('a.name', $search);
                } elseif ($searchField === 'name') {
                    $builder->like('o.name', $search);
                } else {
                    // 전체: 분야 / 지역명 / 선상명
                    $builder->groupStart()
                        ->like('f.name', $search)
                        ->orLike('a.name', $search)
                        ->orLike('o.name', $search)
                        ->groupEnd();
                }
            }
            if ($partnership === 'Y' || $partnership === 'N') {
                $builder->where('o.partnership_YN', $partnership);
            }
            if ($status === 'Y' || $status === 'N') {
                $builder->where('o.status_YN', $status);
            }
            if ($fieldId > 0) {
                $builder->where('o.field_id', $fieldId);
            }
            if ($areaId > 0) {
                $builder->where('o.area_id', $areaId);
            }

            // 등록일 기간 필터 (YYYY-MM-DD)
            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate)) {
                $builder->where('o.created_at >=', $startDate . ' 00:00:00');
            }
            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate)) {
                $builder->where('o.created_at <=', $endDate . ' 23:59:59');
            }

            $total = $builder->countAllResults(false);

            // 계좌번호는 목록에서 제외 (민감정보)
            $items = $builder
                ->select('o.id, o.name, o.field_id, o.area_id, o.area_detail, o.partnership_YN, o.status_YN, o.created_at, f.name as field_name, a.name as area_name')
                ->orderBy('o.id', 'DESC')
                ->limit($perPage, $offset)
                ->get()
                ->getResult();

            return $this->respondSuccess([
                'items'       => $items,
                'total'       => $total,
                'page'        => $page,
                'per_page'    => $perPage,
                'total_pages' => (int) ceil($total / $perPage),
            ]);
        } catch (\Exception $e) {
            log_message('error', 'OnboardController index error: ' . $e->getMessage());
            return $this->respondError('목록 조회 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 등록
     * POST /api/onboard
     */
    public function create()
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        try {
            $payload = $this->request->getJSON(true);
            if (!is_array($payload) || empty($payload)) {
                $payload = $this->request->getPost() ?? [];
            }

            $fieldId = (int) ($payload['field_id'] ?? 0);
            $areaId  = (int) ($payload['area_id'] ?? 0);
            $name    = trim((string) ($payload['name'] ?? ''));

            // 필수값 검증
            if ($fieldId <= 0) {
                return $this->respondError('분야를 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if ($areaId <= 0) {
                return $this->respondError('지역을 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if ($name === '') {
                return $this->respondError('선상명을 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (mb_strlen($name) > 100) {
                return $this->respondError('선상명은 100자 이내로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $db = $this->getDB();

            // 분야 / 지역 존재 확인
            $fieldExists = $db->table('fishing_field')
                ->where('id', $fieldId)->where('deleted_YN', 'N')->countAllResults();
            if ($fieldExists === 0) {
                return $this->respondError('존재하지 않는 분야입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $areaExists = $db->table('fishing_area')
                ->where('id', $areaId)->where('deleted_YN', 'N')->countAllResults();
            if ($areaExists === 0) {
                return $this->respondError('존재하지 않는 지역입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            // Y/N 정규화
            $partnership = (($payload['partnership_YN'] ?? 'N') === 'Y') ? 'Y' : 'N';
            $status      = (($payload['status_YN'] ?? 'Y') === 'N') ? 'N' : 'Y';

            $insertData = [
                'field_id'       => $fieldId,
                'area_id'        => $areaId,
                'name'           => $name,
                'area_detail'    => trim((string) ($payload['area_detail'] ?? '')),
                'tonnage'        => trim((string) ($payload['tonnage'] ?? '')),
                'capacity'       => trim((string) ($payload['capacity'] ?? '')),
                'zip_code'       => trim((string) ($payload['zip_code'] ?? '')),
                'address'        => trim((string) ($payload['address'] ?? '')),
                'address_detail' => trim((string) ($payload['address_detail'] ?? '')),
                'address_refer'  => trim((string) ($payload['address_refer'] ?? '')),
                'lat'            => trim((string) ($payload['lat'] ?? '')),
                'lng'            => trim((string) ($payload['lng'] ?? '')),
                'partnership_YN' => $partnership,
                'status_YN'      => $status,
                'created_at'     => date('Y-m-d H:i:s'),
            ];

            // 제휴인 경우에만 계좌 정보 저장 (비제휴면 빈 값)
            // 계좌번호는 양방향 암호화하여 저장
            if ($partnership === 'Y') {
                $insertData['bank_code']      = trim((string) ($payload['bank_code'] ?? ''));
                $insertData['account_number'] = $this->encryptValue(trim((string) ($payload['account_number'] ?? '')));
                $insertData['account_holder'] = trim((string) ($payload['account_holder'] ?? ''));
            } else {
                $insertData['bank_code']      = '';
                $insertData['account_number'] = '';
                $insertData['account_holder'] = '';
            }

            if (!$db->table($this->table)->insert($insertData)) {
                return $this->respondError('등록에 실패했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
            }

            $newId = $db->insertID();
            $row = $db->table($this->table)->where('id', $newId)->get()->getRow();
            // 응답 시 계좌번호 복호화
            if ($row) {
                $row->account_number = $this->decryptValue($row->account_number);
            }

            return $this->respondSuccess($row, '선상이 등록되었습니다.', ResponseInterface::HTTP_CREATED);
        } catch (\Exception $e) {
            log_message('error', 'OnboardController create error: ' . $e->getMessage());
            return $this->respondError('등록 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 상세 조회
     * GET /api/onboard/:id
     */
    public function show($id = null)
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        if (empty($id)) {
            return $this->respondError('ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
        }

        try {
            $row = $this->getDB()->table($this->table . ' o')
                ->select('o.*, f.name as field_name, a.name as area_name')
                ->join('fishing_field f', 'f.id = o.field_id', 'left')
                ->join('fishing_area a', 'a.id = o.area_id', 'left')
                ->where('o.id', (int) $id)
                ->where('o.deleted_YN', 'N')
                ->get()
                ->getRow();

            if (!$row) {
                return $this->respondError('해당 선상을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            // 계좌번호 복호화
            $row->account_number = $this->decryptValue($row->account_number);

            // 사진 목록 (정렬순)
            $row->photos = $this->getDB()->table('onboard_photos')
                ->where('onboard_id', (int) $id)
                ->orderBy('sort_order', 'ASC')
                ->orderBy('id', 'ASC')
                ->get()
                ->getResult();

            return $this->respondSuccess($row);
        } catch (\Exception $e) {
            log_message('error', 'OnboardController show error: ' . $e->getMessage());
            return $this->respondError('조회 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 수정
     * PUT /api/onboard/:id
     */
    public function update($id = null)
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        if (empty($id)) {
            return $this->respondError('ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
        }

        try {
            $payload = $this->request->getJSON(true);
            if (!is_array($payload) || empty($payload)) {
                $payload = $this->request->getRawInput() ?? [];
            }

            $fieldId = (int) ($payload['field_id'] ?? 0);
            $areaId  = (int) ($payload['area_id'] ?? 0);
            $name    = trim((string) ($payload['name'] ?? ''));

            if ($fieldId <= 0) {
                return $this->respondError('분야를 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if ($areaId <= 0) {
                return $this->respondError('지역을 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if ($name === '') {
                return $this->respondError('선상명을 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (mb_strlen($name) > 100) {
                return $this->respondError('선상명은 100자 이내로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $db = $this->getDB();

            // 대상 존재 확인
            $exists = $db->table($this->table)
                ->where('id', (int) $id)->where('deleted_YN', 'N')->countAllResults();
            if ($exists === 0) {
                return $this->respondError('해당 선상을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            // 분야 / 지역 존재 확인
            $fieldExists = $db->table('fishing_field')
                ->where('id', $fieldId)->where('deleted_YN', 'N')->countAllResults();
            if ($fieldExists === 0) {
                return $this->respondError('존재하지 않는 분야입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            $areaExists = $db->table('fishing_area')
                ->where('id', $areaId)->where('deleted_YN', 'N')->countAllResults();
            if ($areaExists === 0) {
                return $this->respondError('존재하지 않는 지역입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $partnership = (($payload['partnership_YN'] ?? 'N') === 'Y') ? 'Y' : 'N';
            $status      = (($payload['status_YN'] ?? 'Y') === 'N') ? 'N' : 'Y';

            $updateData = [
                'field_id'       => $fieldId,
                'area_id'        => $areaId,
                'name'           => $name,
                'area_detail'    => trim((string) ($payload['area_detail'] ?? '')),
                'tonnage'        => trim((string) ($payload['tonnage'] ?? '')),
                'capacity'       => trim((string) ($payload['capacity'] ?? '')),
                'zip_code'       => trim((string) ($payload['zip_code'] ?? '')),
                'address'        => trim((string) ($payload['address'] ?? '')),
                'address_detail' => trim((string) ($payload['address_detail'] ?? '')),
                'address_refer'  => trim((string) ($payload['address_refer'] ?? '')),
                'lat'            => trim((string) ($payload['lat'] ?? '')),
                'lng'            => trim((string) ($payload['lng'] ?? '')),
                'partnership_YN' => $partnership,
                'status_YN'      => $status,
                'updated_at'     => date('Y-m-d H:i:s'),
            ];

            // 제휴면 계좌 정보 (계좌번호 재암호화), 비제휴면 빈 값
            if ($partnership === 'Y') {
                $updateData['bank_code']      = trim((string) ($payload['bank_code'] ?? ''));
                $updateData['account_number'] = $this->encryptValue(trim((string) ($payload['account_number'] ?? '')));
                $updateData['account_holder'] = trim((string) ($payload['account_holder'] ?? ''));
            } else {
                $updateData['bank_code']      = '';
                $updateData['account_number'] = '';
                $updateData['account_holder'] = '';
            }

            $db->table($this->table)->where('id', (int) $id)->update($updateData);

            $row = $db->table($this->table)->where('id', (int) $id)->get()->getRow();
            if ($row) {
                $row->account_number = $this->decryptValue($row->account_number);
            }

            return $this->respondSuccess($row, '선상이 수정되었습니다.');
        } catch (\Exception $e) {
            log_message('error', 'OnboardController update error: ' . $e->getMessage());
            return $this->respondError('수정 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 사진 삭제 (파일 + DB hard delete)
     * DELETE /api/onboard/photo/:photoId
     */
    public function deletePhoto($photoId = null)
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        if (empty($photoId)) {
            return $this->respondError('사진 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
        }

        try {
            $db = $this->getDB();
            $photo = $db->table('onboard_photos')->where('id', (int) $photoId)->get()->getRow();
            if (!$photo) {
                return $this->respondError('해당 사진을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            // 실제 파일 삭제
            $fullPath = FCPATH . ltrim($photo->file_path, '/');
            if (is_file($fullPath)) {
                @unlink($fullPath);
            }

            $db->table('onboard_photos')->where('id', (int) $photoId)->delete();

            return $this->respondSuccess(null, '사진이 삭제되었습니다.');
        } catch (\Exception $e) {
            log_message('error', 'OnboardController deletePhoto error: ' . $e->getMessage());
            return $this->respondError('사진 삭제 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 사진 업로드 (다중)
     * POST /api/onboard/:id/photos   (multipart, photos[])
     */
    public function uploadPhotos($id = null)
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        if (empty($id)) {
            return $this->respondError('선상 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
        }

        try {
            $db = $this->getDB();

            // 선상 존재 확인
            $exists = $db->table($this->table)
                ->where('id', (int) $id)->where('deleted_YN', 'N')->countAllResults();
            if ($exists === 0) {
                return $this->respondError('해당 선상을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            $files = $this->request->getFileMultiple('photos');
            if (empty($files)) {
                return $this->respondError('업로드할 사진이 없습니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
            $uploadPath = FCPATH . 'uploads/onboard/';
            if (!is_dir($uploadPath)) {
                mkdir($uploadPath, 0755, true);
            }

            // 기존 사진의 최대 sort_order 다음부터 부여
            $maxRow = $db->table('onboard_photos')
                ->selectMax('sort_order')
                ->where('onboard_id', (int) $id)
                ->get()->getRow();
            $order = $maxRow && $maxRow->sort_order !== null ? (int) $maxRow->sort_order + 1 : 0;

            $saved = [];
            foreach ($files as $file) {
                if (!$file->isValid()) {
                    continue;
                }
                // 실제 파일 기반 MIME 검증
                $mime = $file->getMimeType();
                if (!in_array($mime, $allowed, true)) {
                    continue;
                }

                $originalName = $file->getClientName();
                $size = $file->getSize();
                $newName = $file->getRandomName();

                $file->move($uploadPath, $newName);
                $fullPath = $uploadPath . $newName;

                // 이미지 크기 추출
                $width = null;
                $height = null;
                $info = @getimagesize($fullPath);
                if ($info) {
                    $width = $info[0];
                    $height = $info[1];
                }

                $photoData = [
                    'onboard_id'    => (int) $id,
                    'original_name' => $originalName,
                    'stored_name'   => $newName,
                    'file_path'     => '/uploads/onboard/' . $newName,
                    'file_size'     => $size,
                    'mime_type'     => $mime,
                    'width'         => $width,
                    'height'        => $height,
                    'sort_order'    => $order,
                    'created_at'    => date('Y-m-d H:i:s'),
                ];
                $db->table('onboard_photos')->insert($photoData);
                $photoData['id'] = $db->insertID();
                $saved[] = $photoData;
                $order++;
            }

            if (empty($saved)) {
                return $this->respondError('유효한 이미지 파일이 없습니다. (JPG/PNG/GIF/WebP만 허용)', ResponseInterface::HTTP_BAD_REQUEST);
            }

            return $this->respondSuccess($saved, count($saved) . '장의 사진이 업로드되었습니다.', ResponseInterface::HTTP_CREATED);
        } catch (\Exception $e) {
            log_message('error', 'OnboardController uploadPhotos error: ' . $e->getMessage());
            return $this->respondError('사진 업로드 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 선상 삭제 (soft delete)
     * DELETE /api/onboard/:id
     */
    public function delete($id = null)
    {
        $auth = $this->requireAuth();
        if ($auth instanceof ResponseInterface) {
            return $auth;
        }

        if (empty($id)) {
            return $this->respondError('ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
        }

        try {
            $db = $this->getDB();

            $exists = $db->table($this->table)
                ->where('id', (int) $id)
                ->where('deleted_YN', 'N')
                ->countAllResults();
            if ($exists === 0) {
                return $this->respondError('해당 선상을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            $db->table($this->table)
                ->where('id', (int) $id)
                ->update([
                    'deleted_YN' => 'Y',
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);

            return $this->respondSuccess(null, '선상이 삭제되었습니다.');
        } catch (\Exception $e) {
            log_message('error', 'OnboardController delete error: ' . $e->getMessage());
            return $this->respondError('삭제 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 값 암호화 (빈 값은 그대로 빈 문자열)
     */
    private function encryptValue(string $plain): string
    {
        if ($plain === '') {
            return '';
        }
        $encrypter = \Config\Services::encrypter();
        return base64_encode($encrypter->encrypt($plain));
    }

    /**
     * 값 복호화 (실패/빈 값이면 빈 문자열)
     */
    private function decryptValue(?string $cipher): string
    {
        if (empty($cipher)) {
            return '';
        }
        try {
            $encrypter = \Config\Services::encrypter();
            return $encrypter->decrypt(base64_decode($cipher));
        } catch (\Exception $e) {
            log_message('error', 'Account decrypt error: ' . $e->getMessage());
            return '';
        }
    }
}
