<?php

namespace App\Http\Controllers\Web\Auth;

use App\Http\Controllers\Controller;
use App\Repositories\Member\MemberAuthRepository;
use App\Support\LegacyCrypto\CiSeedCrypto;
use App\Rules\RecaptchaV3Rule;
use App\Services\SmsService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;

class FindIdController extends Controller
{
    public function show(Request $request)
    {
        // 세션에 결과가 있으면 3단계로 시작, 인증대기면 2단계, 아니면 1단계
        $sess = $request->session()->get('find_id', []);
        $step = 1;
        if (!empty($sess['result_email_masked'])) $step = 3;
        else if (!empty($sess['sent'])) $step = 2;

        return view('web.auth.find_id', [
            'initialStep' => $step,
            'maskedEmail' => $sess['result_email_masked'] ?? null,
            'phone'       => $sess['phone'] ?? null,
        ]);
    }

    public function sendCode(Request $request)
    {
        logger()->info('HIT sendCode', ['path' => request()->path(), 'host' => request()->getHost()]);

        $rules = [
            'phone' => ['required', 'string', 'max:20'],
        ];

        if (app()->environment('production')) {
            $rules['g-recaptcha-response'] = ['required', new RecaptchaV3Rule('find_id')];
        }

        $v = Validator::make($request->all(), $rules, [
            'phone.required' => '휴대폰 번호를 입력해 주세요.',
            'g-recaptcha-response.required' => '올바른 접근이 아닙니다.',
        ]);

        if ($v->fails()) {
            return response()->json(['ok' => false, 'message' => $v->errors()->first()], 422);
        }

        $phoneRaw = (string) $request->input('phone');
        $phone = $this->normalizeKoreanPhone($phoneRaw);

        if (!$phone) {
            return response()->json(['ok' => false, 'message' => '휴대폰 번호 형식이 올바르지 않습니다.'], 422);
        }

        /** @var CiSeedCrypto $seed */
        $seed = app(CiSeedCrypto::class);

        // DB에 저장된 방식(동일)으로 암호화해서 비교
        $phoneEnc = $seed->encrypt($phone);

        $repo = app(MemberAuthRepository::class);
        $exists = $repo->existsByEncryptedPhone($phoneEnc);

        if (!$exists) {
            //\세션도 만들지 말고, 프론트가 Step1로 돌아가도록 힌트 제공
            return response()->json([
                'ok' => false,
                'code' => 'PHONE_NOT_FOUND',
                'message' => '해당 휴대폰 번호로 가입된 계정을 찾을 수 없습니다. 번호를 다시 확인해 주세요.',
                'step' => 1,
            ], 404);
        }

        // 레이트리밋(휴대폰 기준) - 과도한 발송 방지
        $key = 'findid:send:' . $phone;
        if (RateLimiter::tooManyAttempts($key, 5)) { // 10분에 5회 예시
            $sec = RateLimiter::availableIn($key);
            return response()->json(['ok' => false, 'message' => "요청이 너무 많습니다. {$sec}초 후 다시 시도해 주세요."], 429);
        }
        RateLimiter::hit($key, 600);

        // 6자리 난수 생성
        $code = (string) random_int(100000, 999999);

        // 세션 저장(보안: 실제로는 해시 저장 권장, 여기선 간단 구현)
        $request->session()->put('find_id', [
            'sent' => true,
            'phone' => $phone,
            'code' => password_hash($code, PASSWORD_DEFAULT),
            'code_expires_at' => now()->addMinutes(3)->timestamp,
            'verified' => false,
            'result_email_masked' => null,
        ]);

        // SMS 발송
        try {
            $smsPayload = [
                'from_number' => config('services.sms.from', '1833-4856'), // 기본 발신번호
                'to_number'   => $phone,
                'message'     => "[PIN FOR YOU] 인증번호 {$code} 를 입력해 주세요. (3분 이내)",
                'sms_type'    => 'sms', // 짧으니 sms 고정(원하면 자동 판단으로 빼도 됨)
                // 'country'  => '82', // 필요 시 강제
            ];

            $ok = app(SmsService::class)->send($smsPayload, 'lguplus');

            if (!$ok) {
                // 실패 시 세션 정리(인증 진행 꼬임 방지)
                $request->session()->forget('find_id');
                return response()->json([
                    'ok' => false,
                    'message' => '문자 발송에 실패했습니다. 잠시 후 다시 시도해 주세요.',
                ], 500);
            }
        } catch (\Throwable $e) {
            $request->session()->forget('find_id');

            // 운영에서만 로그 남기기(개발 중엔 디버깅 가능)
            Log::error('FindId SMS send failed', [
                'phone' => $phone,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'ok' => false,
                'message' => '문자 발송 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.',
            ], 500);
        }
        $isLocal = app()->environment(['local', 'development', 'testing']);

        return response()->json([
            'ok' => true,
            'message' => '인증번호를 발송했습니다.',
            'expires_in' => 180,
            'step' => 2,
            //'dev_code' => $isLocal ? $code : null,
        ]);
    }

    public function verify(Request $request)
    {
        $v = Validator::make($request->all(), [
            'code' => ['required', 'digits:6'],
        ], [
            'code.required' => '인증번호를 입력해 주세요.',
            'code.digits' => '인증번호 6자리를 입력해 주세요.',
        ]);

        if ($v->fails()) {
            return response()->json(['ok' => false, 'message' => $v->errors()->first()], 422);
        }

        $sess = $request->session()->get('find_id');
        if (!$sess || empty($sess['sent']) || empty($sess['phone'])) {
            return response()->json(['ok' => false, 'message' => '먼저 인증번호를 요청해 주세요.'], 400);
        }

        if (empty($sess['code_expires_at']) || now()->timestamp > (int)$sess['code_expires_at']) {
            return response()->json(['ok' => false, 'message' => '인증번호가 만료되었습니다. 다시 요청해 주세요.'], 400);
        }

        // 검증 시도 레이트리밋
        $key = 'findid:verify:' . $sess['phone'];
        if (RateLimiter::tooManyAttempts($key, 10)) { // 10분 10회 예시
            $sec = RateLimiter::availableIn($key);
            return response()->json(['ok' => false, 'message' => "시도 횟수가 많습니다. {$sec}초 후 다시 시도해 주세요."], 429);
        }
        RateLimiter::hit($key, 600);

        $code = $request->input('code');
        $ok = password_verify($code, $sess['code'] ?? '');

        if (!$ok) {
            return response()->json(['ok' => false, 'message' => '인증번호가 일치하지 않습니다.'], 422);
        }

        // 인증 성공: 휴대폰 번호로 가입된 "아이디(이메일)"들 조회 (여러개면 전부)
        $phone = (string) ($sess['phone'] ?? '');
        $phone = trim($phone);

        if ($phone === '') {
            return response()->json(['ok' => false, 'message' => '휴대폰 번호가 비어 있습니다.'], 422);
        }

        /** @var CiSeedCrypto $crypto */
        $crypto = app(CiSeedCrypto::class);

        // 키를 넘기지 말고, CiSeedCrypto가 생성자 주입된 userKey로 처리하게 통일
        $phoneEnc = $crypto->encrypt($phone);

        $repo = app(MemberAuthRepository::class);
        $emails = $repo->getEmailsByEncryptedPhone($phoneEnc);

        if (empty($emails)) {
            // 운영에서는 암호문 노출 절대 금지 (지금은 디버그용이면 로그로만)
            // Log::debug('find-id phoneEnc', ['phoneEnc' => $phoneEnc, 'phone' => $phone]);
            return response()->json(['ok' => false, 'message' => '해당 번호로 가입된 계정을 찾을 수 없습니다.'], 404);
        }

        // 마스킹해서 여러개 내려주기
        $maskedEmails = array_map(fn($e) => $this->maskEmail($e), $emails);

        $request->session()->forget('find_id');
        $request->session()->save();

        return response()->json([
            'ok' => true,
            'message' => '인증이 완료되었습니다.',
            'count' => count($maskedEmails),
            'masked_emails' => $maskedEmails,
            //'emails' => $emails,
        ]);
    }


    public function reset(Request $request)
    {
        $request->session()->forget('find_id');
        return response()->json(['ok' => true]);
    }

    private function normalizeKoreanPhone(string $input): ?string
    {
        $digits = preg_replace('/\D+/', '', $input);
        if (!$digits) return null;
        if (Str::startsWith($digits, '010') && strlen($digits) === 11) return $digits;
        if (preg_match('/^01[0-9]{8,9}$/', $digits)) return $digits; // 필요시 범위 조정
        return null;
    }

    private function maskEmail(string $email): string
    {
        $email = trim($email);

        if (!str_contains($email, '@')) {
            return $email;
        }

        [$local, $domain] = explode('@', $email, 2);

        $localLen = mb_strlen($local, 'UTF-8');

        // 너무 짧은 로컬파트는 규칙 완화
        if ($localLen <= 2) {
            // ab@ -> a*@ 정도
            $head = mb_substr($local, 0, 1, 'UTF-8');
            return $head . '*' . '@' . $domain;
        }

        if ($localLen <= 5) {
            // abcde -> ab*** (끝 1자리만 힌트)
            $head = mb_substr($local, 0, 2, 'UTF-8');
            $tail = mb_substr($local, -1, 1, 'UTF-8');
            return $head . str_repeat('*', max(1, $localLen - 3)) . $tail . '@' . $domain;
        }

        // ✅ 기본 규칙: 앞 3글자 + ***** + 뒤 2글자
        $head = mb_substr($local, 0, 3, 'UTF-8');
        $tail = mb_substr($local, -2, 2, 'UTF-8');

        // 별 개수: 최소 5개, 너무 길면 로컬 길이에 맞게 조정
        $stars = max(5, $localLen - 5); // head3 + tail2 = 5
        return $head . str_repeat('*', $stars) . $tail . '@' . $domain;
    }

}
