<?php

namespace App\Http\Controllers\Web\Auth;

use App\Http\Controllers\Controller;
use App\Repositories\Member\MemberAuthRepository;
use App\Services\Danal\DanalAuthtelService;
use App\Rules\RecaptchaV3Rule;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;

class RegisterController extends Controller
{
    public function showStep0(Request $request)
    {
        //기존 인증 받다가 중지된 정보가 있다면 세션값 지우기
        $this->clearSession($request, 'signup');
        $this->clearSession($request, 'register');
        return view('web.auth.register');
    }

    public function showTerms(Request $request)
    {
        // Step0 스킵 방지 (최소)
        if (($request->session()->get('signup.step') ?? 0) < 1) {
            return redirect()->route('web.auth.register');
        }

        return view('web.auth.register_terms');
    }


    public function postPhoneCheck(Request $request, MemberAuthRepository $repo)
    {
        $v = Validator::make($request->all(), [
            'phone' => ['required', 'string', 'max:20'],
            'carrier' => ['required', 'in:01,02,03,04,05,06'],  //01:SKT,02:KT,03:LGU+,04:SKT(알뜰폰),05:KT(알뜰폰),06:LGU+(알뜰폰)'
            'g-recaptcha-response' => ['required', new RecaptchaV3Rule('register_phone_check')],
        ], [
            'phone.required' => '휴대폰 번호를 입력해 주세요.',
            'carrier.required' => '통신사를 선택해 주세요.',
            'carrier.in' => '통신사 선택 값이 올바르지 않습니다.',
            'g-recaptcha-response.required' => '보안 검증에 실패했습니다. 다시 시도해 주세요.',
        ]);

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

        /* 회원가입 필터 아이피로 차단 및 관리자 알림*/
        $ip = $request->ip();
        $ip4c = implode('.', array_slice(explode('.', $ip), 0, 3)); //C-CLASS CHECK (210.96.177)
        if (!$request->session()->has('signup.ipf_result')) {
            $ipCheck = $repo->precheckJoinIpFilterAndLog([
                'mem_no'     => 0,
                'cell_corp'  => $request->input('carrier'),
                'cell_phone' => $request->input('phone'),
                'email'      => '-',
                'ip4'        => $ip,
                'ip4_c'      => $ip4c,
            ]);

            $request->session()->put('signup.ipf_result', $ipCheck['result']); // A/S/P
            $request->session()->put('signup.ipf_seq', (int)($ipCheck['seq'] ?? 0));

            if ($ipCheck['result'] === 'A') {
                // 가입 차단
                return response()->json([
                    'ok' => false,
                    'message' => '회원가입에 문제가 발생하였습니다. 고객센터에 문의하세요!',
                ], 403);
            }
        }
        /* 회원가입 필터 아이피로 차단 및 관리자 알림*/

        $map = [        //다날로 보내는 값
            '01' => 'SKT', '02' => 'KTF', '03' => 'LGT',
            '04' => 'MVNO','05' => 'MVNO','06' => 'MVNO',
        ];

        $result = $repo->step0PhoneCheck(
            (string) $request->input('phone'),
            (string) $request->input('carrier'),
        );

        $danalCarrier = $map[$result['carrier']] ?? null;

        if (!($result['ok'] ?? false)) {
            $reason = $result['reason'] ?? 'error';

            // blocked류만 403, 그 외는 422(원하면 already_member는 200으로 바꿔도 됨)
            $status = in_array($reason, ['blocked', 'blocked_ip'], true) ? 403 : 422;
            return response()->json([
                'ok' => false,
                'reason' => $reason,
                'message' => $result['message'] ?? '처리에 실패했습니다.',
                'redirect' => $result['redirect'] ?? null,
            ], $status);
        }

        $request->session()->put('signup.step', 1);
        $request->session()->put('signup.phone', $result['phone']);
        $request->session()->put('signup.carrier', $danalCarrier);
        $request->session()->save();

        return response()->json([
            'ok' => true,
            'reason' => $result['reason'] ?? 'ok',
            'message' => $result['message'] ?? '',
            'redirect' => $result['redirect'] ?? null,
            'phone' => $result['phone'] ?? null,
            'carrier' => $danalCarrier,
        ], 200);
    }

    public function termsSubmit(Request $request)
    {
        $v = Validator::make($request->all(), [
            'agree_terms' => ['required', 'in:1'],
            'agree_privacy' => ['required', 'in:1'],
            'agree_age' => ['required', 'in:1'],
            'agree_marketing' => ['nullable', 'in:1'],
        ], [
            'agree_terms.required' => '이용약관에 동의해 주세요.',
            'agree_privacy.required' => '개인정보 수집·이용에 동의해 주세요.',
            'agree_age.required' => '만 14세 이상만 가입할 수 있습니다.',
        ]);

        if ($v->fails()) {
            // AJAX면 JSON으로
            if ($request->expectsJson()) {
                return response()->json([
                    'ok' => false,
                    'message' => $v->errors()->first(),
                    'errors' => $v->errors(),
                ], 422);
            }

            // 일반 submit이면 기존처럼
            return back()->withErrors($v)->withInput();
        }

        // 약관 동의값 저장(세션)
        $request->session()->put('register.terms', [
            'agree_terms' => true,
            'agree_privacy' => true,
            'agree_age' => true,
            'agree_marketing' => (bool)$request->input('agree_marketing'),
            'agreed_at' => now()->toDateTimeString(),
            'ip' => $request->ip(),
            'ua' => substr((string)$request->userAgent(), 0, 500),
        ]);
        $request->session()->save();

        // AJAX면: 다날 준비값 생성 후 popup 정보 반환
        if ($request->expectsJson()) {
            $danal = app(\App\Services\Danal\DanalAuthtelService::class)->prepare([
                'targetUrl' => route('web.auth.register.danal.result'),
                'backUrl'   => route('web.auth.register.terms'),
                'cpTitle'   => request()->getHost(),
            ]);

            if (!($danal['ok'] ?? false)) {
                return response()->json([
                    'ok' => false,
                    'message' => $danal['message'] ?? '본인인증 준비에 실패했습니다. 잠시 후 다시 시도해 주세요.',
                ], 500);
            }

            // 필요하면 트랜잭션 정보 세션 저장
            $request->session()->put('register.danal', [
                'txid' => $danal['txid'] ?? null,
                'created_at' => now()->toDateTimeString(),
            ]);
            $request->session()->save();

            return response()->json([
                'ok' => true,
                'reason' => 'danal_ready',
                'popup' => [
                    'url' => route('web.auth.register.danal.start'),
                    'fields' => $danal['fields'], // Start.php로 보낼 hidden inputs
                ],
            ]);
        }

        return redirect()->route('web.auth.register.terms')
            ->with('ui_dialog', [
                'type' => 'alert',
                'title' => '완료',
                'message' => "약관 동의가 저장되었습니다.\n\n다음 단계(본인인증)를 진행합니다.",
            ]);
    }


    public function danalStart(Request $request)
    {
        // fields는 JSON으로 받을 것
        $fieldsJson = (string) $request->input('fields', '');
        $fields = json_decode($fieldsJson, true);

        if (!is_array($fields) || empty($fields)) {
            abort(400, 'Invalid Danal fields');
        }

        $platform = strtolower((string) $request->input('platform', ($fields['platform'] ?? '')));
        $isMobile = false;
        if ($platform === 'mobile') {
            $isMobile = true;
        } elseif ($platform === 'web') {
            $isMobile = false;
        } else {
            $ua = (string) $request->header('User-Agent', '');
            $isMobile = (bool) preg_match('/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i', $ua);
        }

        $fields['IsDstAddr'] = $request->session()->get('signup.phone');
        $fields['IsCarrier'] = $request->session()->get('signup.carrier');

        $action = $isMobile
            ? 'https://wauth.teledit.com/Danal/WebAuth/Mobile/Start.php'
            : 'https://wauth.teledit.com/Danal/WebAuth/Web/Start.php';

        unset($fields['platform']);

        return view('web.auth.danal_autosubmit', [
            'action' => $action,
            'fields' => $fields,
            'isMobile' => $isMobile,
        ]);
    }


    public function danalResult(Request $request, DanalAuthtelService $danal, MemberAuthRepository $repo)
    {
        $payload = $request->all();

        if (config('app.debug')) {
            Log::info('[DANAL][RESULT] payload keys', [
                'method' => $request->method(),
                'url' => $request->fullUrl(),
                'keys' => array_keys($payload),
            ]);
            Log::info('[DANAL][RESULT] payload', $this->maskDanalPayloadForLog($payload));
        }

        $tid = (string)($payload['TID'] ?? '');
        if ($tid === '') {
            return response()->view('web.auth.danal_finish_top', [
                'ok' => false,
                'message' => 'TID가 없습니다.',
                'redirect' => route('web.auth.register.terms'),
            ]);
        }

        //  CI와 동일: TID로 CONFIRM 호출해서 RETURNCODE를 받는다 (dndata 사용 안함)
        $res = $danal->confirm($tid, 0, 1);

        if (config('app.debug')) {
            Log::info('[DANAL][CONFIRM] keys', ['keys' => array_keys($res)]);
            Log::info('[DANAL][CONFIRM] res', $this->maskDanalPayloadForLog($res));
        }

        //repo로 로그 1차 저장” (성공/실패 무조건 저장)
        $logSeq = $repo->insertDanalAuthLog('J', (array)$res);
        if ($logSeq > 0) {
            $request->session()->put('register.danal_log_seq', $logSeq);
        }

        $ok = (($res['RETURNCODE'] ?? '') === '0000');

        if (!$ok) {
            return response()->view('web.auth.danal_finish_top', [
                'ok' => false,
                'message' => ($res['RETURNMSG'] ?? '본인인증에 실패했습니다.') . ' (' . ($res['RETURNCODE'] ?? 'NO_CODE') . ')',
                'redirect' => route('web.auth.register.terms'),
            ]);
        }

        /* 다날 통신 성공 후 체크*/
        $normPhone = function (?string $p) {
            $p = preg_replace('/\D+/', '', (string)$p);
            return $p;
        };

        $signupPhone = $normPhone(data_get($request->session()->get('signup', []), 'phone'));       //처음 입력 전화번호
        $passPhone   = $normPhone($res['PHONE'] ?? null);                                                 //인증받은 전화번호

        // signup.phone vs PASS PHONE 비교
        if ($signupPhone === '' || $passPhone === '' || $signupPhone !== $passPhone) {
            $request->session()->flush();
            $request->session()->save();

            return response()->view('web.auth.danal_finish_top', [
                'ok' => false,
                'message' => '인증에 사용한 휴대폰 번호가 가입 진행 번호와 일치하지 않습니다. 다시 진행해 주세요.',
                'redirect' => route('web.auth.register'),
            ]);
        }

        // 통신사 제한
        $carrier = (string)($res['CARRIER'] ?? '');
        $blockedCarriers = ['SKT_MVNO', 'KT_MVNO', 'LGT_MVNO']; // 알뜰폰
        if (in_array($carrier, $blockedCarriers, true)) {
            $request->session()->flush();
            $request->session()->save();

            return response()->view('web.auth.danal_finish_top', [
                'ok' => false,
                'message' => '죄송합니다. 알뜰폰(또는 일부 통신사) 휴대전화는 가입할 수 없습니다.',
                'redirect' => route('web.auth.register'),
            ]);
        }

        //  성공: 다음 단계에서 쓸 데이터 세션 저장
        $request->session()->put('register.pass_verified', true);
        $request->session()->put('register.pass_payload', $res);
        $request->session()->save();

        return response()->view('web.auth.danal_finish_top', [
            'ok' => true,
            'message' => '본인인증이 완료되었습니다.',
            'redirect' => route('web.auth.register.profile'),
        ]);
    }

    public function showProfileForm(Request $request)
    {
        if (!$request->session()->get('register.pass_verified')) {
            return redirect()->route('web.auth.register.terms')
                ->with('ui_dialog', [
                    'type'=>'alert',
                    'title'=>'안내',
                    'message'=>'본인인증 후 진행해 주세요.',
                ]);
        }

        return view('web.auth.profile');
    }

    public function checkLoginId(Request $request, MemberAuthRepository $repo)
    {
        $v = Validator::make($request->all(), [
            'login_id' => ['required', 'string', 'max:60', 'email'],
        ], [
            'login_id.required' => '아이디(이메일)를 입력해 주세요.',
            'login_id.email' => '이메일 형식으로 입력해 주세요.',
        ]);

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

        $email = (string) $request->input('login_id');

        // ✅ repo에서 mem_info.email 중복 체크
        $exists = $repo->existsEmail($email);

        return response()->json([
            'ok' => !$exists,
            'message' => $exists ? '이미 사용 중인 아이디입니다.' : '사용 가능한 아이디입니다.',
        ]);
    }

    public function submitProfile(Request $request, MemberAuthRepository $repo)
    {
        // 0) PASS 인증 안됐으면 컷
        if (!$request->session()->get('register.pass_verified')) {
            return redirect()->route('web.auth.register.terms')
                ->with('ui_dialog', [
                    'type' => 'alert',
                    'title' => '안내',
                    'message' => '본인인증 후 진행해 주세요.',
                ]);
        }

        // 1) 입력값 검증 (아이디=이메일)
        $v = Validator::make($request->all(), [
            'login_id' => ['required', 'string', 'email', 'max:60'],
            'password' => [
                'required', 'string', 'min:8', 'max:20',
                'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[^A-Za-z0-9\s]).+$/'
            ],
            'password_confirmation' => ['required', 'same:password'],
            'pin2' => ['required', 'digits:4'],
            'pin2_confirmation' => ['required', 'same:pin2'],
        ], [
            'login_id.required' => '아이디(이메일)를 입력해 주세요.',
            'login_id.email' => '아이디는 이메일 형식이어야 합니다.',
            'password.required' => '비밀번호를 입력해 주세요.',
            'password.min' => '비밀번호는 8자리 이상이어야 합니다.',
            'password.max' => '비밀번호는 20자리를 초과할 수 없습니다.',
            'password.regex' => '비밀번호는 영문+숫자+특수문자를 포함해야 합니다.',
            'password_confirmation.same' => '비밀번호 확인이 일치하지 않습니다.',
            'pin2.required' => '2차 비밀번호(숫자 4자리)를 입력해 주세요.',
            'pin2.digits' => '2차 비밀번호는 숫자 4자리여야 합니다.',
            'pin2_confirmation.same' => '2차 비밀번호 확인이 일치하지 않습니다.',
        ]);

        if ($v->fails()) {
            return back()->withErrors($v)->withInput();
        }

        // 2) 아이디(=이메일) 정규화
        $email = strtolower(trim((string)$request->input('login_id')));

        // 3) 중복 체크는 Repository로만
        if ($repo->existsEmail($email)) {
            return back()->withErrors(['login_id' => '이미 사용 중인 아이디입니다.'])->withInput();
        }

        // 4) PASS payload + signup 세션값 가져오기
        $pv = (array) $request->session()->get('register.pass_payload', []);
        $signupPhone   = (string) $request->session()->get('signup.phone', '');
        $signupCarrier = (string) $request->session()->get('signup.carrier', '');

        if ($signupPhone !== $pv['PHONE'] || $signupCarrier !== $pv['CARRIER']) {
            return back()->withErrors(['login_id' => '처음등록한 전화번호와 인증받은 전화번호 정보가 일치 하지 않습니다..'])->withInput();
        }


        // 5) 가공(서버에서 최종 사용 데이터 구성)
        $final = [
            // 회원 입력
            'email' => $email,
            'password_plain' => (string)$request->input('password'), // 실제 저장은 Hash로 (아래에서 처리)
            'pin2_plain'     => (string) $request->input('pin2'),
            // PASS 인증 결과
            'pass' => [
                'return_code' => $pv['RETURNCODE'] ?? null,
                'tid'         => $pv['TID'] ?? null,
                'name'        => $pv['NAME'] ?? null,
                'dob'         => $pv['DOB'] ?? null,
                'sex'         => $pv['SEX'] ?? null,

                'foreigner'   => $pv['FOREIGNER'] ?? null,
                'phone'       => $pv['PHONE'] ?? $signupPhone,
                'carrier'     => $pv['CARRIER'] ?? $signupCarrier,
                'ci'          => $pv['CI'] ?? null,
                'di'          => $pv['DI'] ?? null,
            ],
            'meta' => [
                'ip' => $request->ip(),
                'ua' => substr((string)$request->userAgent(), 0, 200),
            ],
        ];

        // 비밀번호는 마스킹/제거
        $logFinal = $final;
        $logFinal['password_plain'] = '***masked***';
        $logFinal['pin2_plain']     = '***masked***';

        // 6) 컨트롤러에서 "넘어온 값" 확인: 로그로 보기
        Log::info('[register.profile.submit] payload', $logFinal);

        // 7) 여기부터 실제 저장 로직 (Repository로 위임)
        try {
            $res = $repo->createMemberFromSignup($final, $request->session()->all());

            // 성공 처리 후 세션 정리/이동
            $this->clearSession($request, 'signup');
            $this->clearSession($request, 'register');

            return redirect()->route('web.auth.login')
                ->with('ui_dialog', [
                    'type'=>'alert',
                    'title'=>'완료',
                    'message'=>'가입이 완료되었습니다. 로그인해 주세요.',
                ]);

        } catch (\Throwable $e) {
            Log::error('[register.profile.submit] commit failed', [
                'email' => $final['email'] ?? null,
                'err' => $e->getMessage(),
                'trace' => substr($e->getTraceAsString(), 0, 2000),
            ]);

            //  PASS 세션은 살아있게 두고(=register/pass 유지),
            //  입력값은 withInput()으로 다시 채워서 profile로 복귀
            return redirect()->route('web.auth.register.profile')
                ->withInput()
                ->with('ui_dialog', [
                    'type' => 'alert',
                    'title' => '가입 실패',
                    'message' => '저장 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.',
                ]);
        }

    }



    private function maskDanalPayloadForLog(array $payload): array
    {
        $masked = $payload;

        $sensitiveKeys = [
            'CI','DI','NAME','BIRTH','SEX','GENDER','TEL','PHONE','MOBILE',
            'TID','TXID','TOKEN','ENC','CERT','SSN'
        ];

        foreach ($masked as $k => $v) {
            $keyUpper = strtoupper((string)$k);
            foreach ($sensitiveKeys as $sk) {
                if (str_contains($keyUpper, $sk)) {
                    $masked[$k] = '***';
                    break;
                }
            }
        }

        return $masked;
    }

    private function clearSession(Request $request, string $key = 'signup'): void
    {
        $request->session()->forget($key);
    }

}

