<?php

namespace App\Controllers\Api;

use CodeIgniter\HTTP\ResponseInterface;

class UsersController extends BaseApiController
{
    protected $format = 'json';
    protected $table = 'users';

    private const ALLOWED_AREAS = ['남해', '동해', '민물', '서해', '제주'];

    /**
     * 아이디 찾기 — 이름 + 핸드폰으로 조회 → 마스킹된 아이디 반환
     * POST /api/users/find-id
     */
    public function findId()
    {
        try {
            $payload = $this->request->getJSON(true);
            $name = trim((string) ($payload['name'] ?? ''));
            $phoneDigits = preg_replace('/[^0-9]/', '', (string) ($payload['phone'] ?? ''));

            if ($name === '') return $this->respondError('이름을 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            if (!preg_match('/^01[016789]\d{7,8}$/', $phoneDigits)) {
                return $this->respondError('핸드폰 번호를 올바르게 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $phoneFormatted = $this->formatPhone($phoneDigits);

            $user = $this->getDB()->table($this->table)
                ->where('name', $name)
                ->where('phone', $phoneFormatted)
                ->where('deleted_YN', 'N')
                ->get()
                ->getRow();

            if (!$user) {
                return $this->respondError('일치하는 회원 정보가 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            return $this->respondSuccess([
                'username_masked' => $this->maskUsername($user->username),
                'signup_type'     => $user->signup_type,
                'created_at'      => $user->created_at,
            ], '아이디 조회 성공');
        } catch (\Exception $e) {
            log_message('error', 'findId error: ' . $e->getMessage());
            return $this->respondError('조회 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 비밀번호 재설정 — 본인 확인 (아이디+이름+핸드폰)
     * POST /api/users/verify-for-reset
     * 일치하면 10분 짜리 임시 토큰 발급
     */
    public function verifyForReset()
    {
        try {
            $payload = $this->request->getJSON(true);
            $username = trim((string) ($payload['username'] ?? ''));
            $name = trim((string) ($payload['name'] ?? ''));
            $phoneDigits = preg_replace('/[^0-9]/', '', (string) ($payload['phone'] ?? ''));

            if ($username === '' || $name === '') {
                return $this->respondError('정보를 모두 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (!preg_match('/^01[016789]\d{7,8}$/', $phoneDigits)) {
                return $this->respondError('핸드폰 번호를 올바르게 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $phoneFormatted = $this->formatPhone($phoneDigits);
            $db = $this->getDB();

            $user = $db->table($this->table)
                ->where('username', $username)
                ->where('name', $name)
                ->where('phone', $phoneFormatted)
                ->where('deleted_YN', 'N')
                ->get()
                ->getRow();

            if (!$user) {
                return $this->respondError('일치하는 회원 정보가 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            // 소셜 가입자는 비밀번호 재설정 불가
            if ($user->signup_type !== 'local') {
                return $this->respondError(
                    '소셜 가입 회원입니다. (' . $user->signup_type . ')',
                    ResponseInterface::HTTP_BAD_REQUEST
                );
            }

            // 10분짜리 임시 토큰 발급
            $token = bin2hex(random_bytes(32));
            $expiresAt = date('Y-m-d H:i:s', strtotime('+10 minutes'));
            $db->table('user_tokens')->insert([
                'user_id'    => $user->id,
                'token'      => $token,
                'expires_at' => $expiresAt,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->respondSuccess([
                'reset_token' => $token,
                'expires_at'  => $expiresAt,
            ], '본인 확인 완료');
        } catch (\Exception $e) {
            log_message('error', 'verifyForReset error: ' . $e->getMessage());
            return $this->respondError('확인 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 비밀번호 재설정 실제 적용
     * POST /api/users/reset-password
     */
    public function resetPassword()
    {
        try {
            $payload = $this->request->getJSON(true);
            $resetToken = trim((string) ($payload['reset_token'] ?? ''));
            $newPassword = (string) ($payload['new_password'] ?? '');

            if ($resetToken === '' || $newPassword === '') {
                return $this->respondError('정보를 모두 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (!preg_match('/^(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]).{8,}$/', $newPassword)) {
                return $this->respondError('비밀번호는 영문 소문자+숫자+특수문자 8자 이상으로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $db = $this->getDB();
            $tokenRow = $db->table('user_tokens')
                ->where('token', $resetToken)
                ->where('expires_at >', date('Y-m-d H:i:s'))
                ->get()
                ->getRow();

            if (!$tokenRow) {
                return $this->respondError('유효하지 않거나 만료된 인증입니다.', ResponseInterface::HTTP_UNAUTHORIZED);
            }

            $user = $db->table($this->table)
                ->where('id', (int) $tokenRow->user_id)
                ->where('deleted_YN', 'N')
                ->get()
                ->getRow();

            if (!$user) {
                return $this->respondError('회원 정보를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
            }

            // 이전 비밀번호와 동일하면 거부
            if (password_verify($newPassword, $user->password)) {
                return $this->respondError('이전과 다른 비밀번호를 입력해 주세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            // 아이디 포함 거부
            if (stripos($newPassword, $user->username) !== false) {
                return $this->respondError('비밀번호에 아이디를 포함할 수 없습니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            // 비밀번호 업데이트
            $db->table($this->table)->where('id', $user->id)->update([
                'password'   => password_hash($newPassword, PASSWORD_DEFAULT),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            // 보안상 해당 사용자의 모든 토큰 삭제 (강제 로그아웃)
            $db->table('user_tokens')->where('user_id', $user->id)->delete();

            return $this->respondSuccess(null, '비밀번호가 변경되었습니다.');
        } catch (\Exception $e) {
            log_message('error', 'resetPassword error: ' . $e->getMessage());
            return $this->respondError('변경 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 아이디 마스킹 — hong****ng 같은 형태
     */
    private function maskUsername(string $username): string
    {
        $len = strlen($username);
        if ($len <= 4) {
            return substr($username, 0, 1) . str_repeat('*', max(0, $len - 1));
        }
        if ($len <= 6) {
            return substr($username, 0, 2) . str_repeat('*', $len - 4) . substr($username, -2);
        }
        return substr($username, 0, 4) . str_repeat('*', $len - 6) . substr($username, -2);
    }

    /**
     * 핸드폰 숫자 → 010-XXXX-XXXX 형식
     */
    private function formatPhone(string $digits): string
    {
        if (strlen($digits) === 11) {
            return substr($digits, 0, 3) . '-' . substr($digits, 3, 4) . '-' . substr($digits, 7);
        }
        return substr($digits, 0, 3) . '-' . substr($digits, 3, 3) . '-' . substr($digits, 6);
    }

    /**
     * 회원 로그인
     * POST /api/users/login
     */
    public function login()
    {
        try {
            $payload = $this->request->getJSON(true);
            if (!is_array($payload)) $payload = [];

            $username = trim((string) ($payload['username'] ?? ''));
            $password = (string) ($payload['password'] ?? '');
            $autoLogin = !empty($payload['auto_login']);

            if ($username === '' || $password === '') {
                return $this->respondError('아이디와 비밀번호를 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $db = $this->getDB();
            $user = $db->table($this->table)
                ->where('username', $username)
                ->where('deleted_YN', 'N')
                ->get()
                ->getRow();

            if (!$user) {
                return $this->respondError('아이디 또는 비밀번호가 일치하지 않습니다.', ResponseInterface::HTTP_UNAUTHORIZED);
            }

            // 계정 상태 확인
            if ($user->status === 'inactive') {
                return $this->respondError('비활성화된 계정입니다.', ResponseInterface::HTTP_FORBIDDEN);
            }
            if ($user->status === 'suspended') {
                return $this->respondError('정지된 계정입니다. 고객센터에 문의하세요.', ResponseInterface::HTTP_FORBIDDEN);
            }

            // 비밀번호 검증
            if (!password_verify($password, $user->password)) {
                return $this->respondError('아이디 또는 비밀번호가 일치하지 않습니다.', ResponseInterface::HTTP_UNAUTHORIZED);
            }

            // last_login_at 업데이트
            $now = date('Y-m-d H:i:s');
            $db->table($this->table)->where('id', $user->id)->update([
                'last_login_at' => $now,
            ]);

            // 토큰 발급 + 저장 (자동로그인: 30일 / 일반: 24시간)
            $token = bin2hex(random_bytes(32));
            $expiresAt = $autoLogin
                ? date('Y-m-d H:i:s', strtotime('+30 days'))
                : date('Y-m-d H:i:s', strtotime('+24 hours'));

            $db->table('user_tokens')->insert([
                'user_id'    => $user->id,
                'token'      => $token,
                'expires_at' => $expiresAt,
                'created_at' => $now,
            ]);

            return $this->respondSuccess([
                'token'      => $token,
                'expires_at' => $expiresAt,
                'user' => [
                    'id'           => (int) $user->id,
                    'username'     => $user->username,
                    'nickname'     => $user->nickname,
                    'name'         => $user->name,
                    'phone'        => $user->phone,
                    'prefer_area'  => $user->prefer_area,
                    'profile_image'=> $user->profile_image,
                ],
            ], '로그인 성공');
        } catch (\Exception $e) {
            log_message('error', 'login error: ' . $e->getMessage());
            return $this->respondError('로그인 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 회원 로그아웃
     * POST /api/users/logout
     */
    public function logout()
    {
        try {
            $authHeader = $this->getAuthHeader();
            if (!empty($authHeader)) {
                $token = str_replace('Bearer ', '', $authHeader);
                if (!empty($token)) {
                    $this->getDB()->table('user_tokens')->where('token', $token)->delete();
                }
            }
            return $this->respondSuccess(null, '로그아웃 성공');
        } catch (\Exception $e) {
            log_message('error', 'logout error: ' . $e->getMessage());
            return $this->respondError('로그아웃 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 아이디 중복 확인
     * POST /api/users/check-username
     */
    public function checkUsername()
    {
        try {
            $payload = $this->request->getJSON(true);
            $username = trim((string) ($payload['username'] ?? ''));

            if ($username === '') {
                return $this->respondError('아이디를 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (!preg_match('/^[a-zA-Z0-9]{6,20}$/', $username)) {
                return $this->respondError('영문/숫자 6~20자로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $exists = $this->getDB()->table($this->table)
                ->where('username', $username)
                ->where('deleted_YN', 'N')
                ->countAllResults();

            if ($exists > 0) {
                return $this->respondError('이미 사용 중인 아이디입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            return $this->respondSuccess(null, '사용 가능한 아이디입니다.');
        } catch (\Exception $e) {
            log_message('error', 'checkUsername error: ' . $e->getMessage());
            return $this->respondError('확인 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 닉네임 중복 확인
     * POST /api/users/check-nickname
     */
    public function checkNickname()
    {
        try {
            $payload = $this->request->getJSON(true);
            $nickname = trim((string) ($payload['nickname'] ?? ''));

            if ($nickname === '') {
                return $this->respondError('닉네임을 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (mb_strlen($nickname) < 2 || mb_strlen($nickname) > 20) {
                return $this->respondError('닉네임은 2~20자로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            $exists = $this->getDB()->table($this->table)
                ->where('nickname', $nickname)
                ->where('deleted_YN', 'N')
                ->countAllResults();

            if ($exists > 0) {
                return $this->respondError('이미 사용 중인 닉네임입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            return $this->respondSuccess(null, '사용 가능한 닉네임입니다.');
        } catch (\Exception $e) {
            log_message('error', 'checkNickname error: ' . $e->getMessage());
            return $this->respondError('확인 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 회원가입
     * POST /api/users/signup
     */
    public function signup()
    {
        try {
            $payload = $this->request->getJSON(true);
            if (!is_array($payload)) $payload = [];

            $username       = trim((string) ($payload['username'] ?? ''));
            $password       = (string) ($payload['password'] ?? '');
            $name           = trim((string) ($payload['name'] ?? ''));
            $phone          = trim((string) ($payload['phone'] ?? ''));
            $nickname       = trim((string) ($payload['nickname'] ?? ''));
            $preferArea     = trim((string) ($payload['prefer_area'] ?? ''));
            $marketingAgree = (($payload['marketing_agree_YN'] ?? 'N') === 'Y') ? 'Y' : 'N';

            // 검증
            if (!preg_match('/^[a-zA-Z0-9]{6,20}$/', $username)) {
                return $this->respondError('아이디는 영문/숫자 6~20자로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if (!preg_match('/^(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]).{8,}$/', $password)) {
                return $this->respondError('비밀번호는 영문 소문자+숫자+특수문자 조합 8자 이상으로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            if ($name === '' || mb_strlen($name) > 50) {
                return $this->respondError('이름을 올바르게 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            // 핸드폰 정규화: 숫자만 추출 후 0XX-XXXX-XXXX 형식으로
            // 010 / 011 / 016 / 017 / 018 / 019 모두 허용 (10~11자리)
            $phoneDigits = preg_replace('/[^0-9]/', '', $phone);
            if (!preg_match('/^01[016789]\d{7,8}$/', $phoneDigits)) {
                return $this->respondError('핸드폰 번호를 올바르게 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            // 11자리: 3-4-4 / 10자리: 3-3-4
            if (strlen($phoneDigits) === 11) {
                $phoneFormatted = substr($phoneDigits, 0, 3) . '-' . substr($phoneDigits, 3, 4) . '-' . substr($phoneDigits, 7);
            } else {
                $phoneFormatted = substr($phoneDigits, 0, 3) . '-' . substr($phoneDigits, 3, 3) . '-' . substr($phoneDigits, 6);
            }

            if (mb_strlen($nickname) < 2 || mb_strlen($nickname) > 20) {
                return $this->respondError('닉네임은 2~20자로 입력하세요.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            // 선호지역 검증
            $preferAreaNormalized = null;
            if ($preferArea !== '') {
                $areas = array_filter(array_map('trim', explode(',', $preferArea)));
                foreach ($areas as $a) {
                    if (!in_array($a, self::ALLOWED_AREAS, true)) {
                        return $this->respondError('잘못된 선호지역입니다.', ResponseInterface::HTTP_BAD_REQUEST);
                    }
                }
                $preferAreaNormalized = implode(',', array_values(array_unique($areas)));
            }

            $db = $this->getDB();

            // 중복 체크
            $userExists = $db->table($this->table)
                ->where('username', $username)
                ->where('deleted_YN', 'N')
                ->countAllResults();
            if ($userExists > 0) {
                return $this->respondError('이미 사용 중인 아이디입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }
            $nickExists = $db->table($this->table)
                ->where('nickname', $nickname)
                ->where('deleted_YN', 'N')
                ->countAllResults();
            if ($nickExists > 0) {
                return $this->respondError('이미 사용 중인 닉네임입니다.', ResponseInterface::HTTP_BAD_REQUEST);
            }

            // INSERT
            $db->table($this->table)->insert([
                'username'           => $username,
                'password'           => password_hash($password, PASSWORD_DEFAULT),
                'nickname'           => $nickname,
                'name'               => $name,
                'phone'              => $phoneFormatted,
                'prefer_area'        => $preferAreaNormalized,
                'signup_type'        => 'local',
                'marketing_agree_YN' => $marketingAgree,
                'status'             => 'active',
                'deleted_YN'         => 'N',
                'created_at'         => date('Y-m-d H:i:s'),
            ]);
            $newId = $db->insertID();

            return $this->respondSuccess(
                ['id' => $newId, 'username' => $username, 'nickname' => $nickname],
                '회원가입이 완료되었습니다.',
                ResponseInterface::HTTP_CREATED
            );
        } catch (\Exception $e) {
            log_message('error', 'signup error: ' . $e->getMessage());
            return $this->respondError('회원가입 중 오류: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
}
