<?php

namespace App\Services;

use App\Models\Member\MemInfo;
use App\Support\LegacyCrypto\CiSeedCrypto;
use App\Support\LegacyCrypto\CiPassword;
use App\Support\Legacy\LoginReason;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;

class MemInfoService
{
    /**
     * CI: mem_email_vali()
     */
    public function emailInfo(string $email): ?MemInfo
    {
        return MemInfo::query()
            ->select(['mem_no','stat_3','dt_req_out','email'])
            ->where('email', strtolower($email))
            ->first();
    }

    /**
     * CI: mem_reg() (간소화 버전)
     * - 실제로는 validation은 FormRequest에서 처리 권장
     */
    public function register(array $data): MemInfo
    {
        return DB::transaction(function () use ($data) {

            $email = strtolower((string)($data['email'] ?? ''));

            // 중복 체크 + 잠금 (CI for update)
            $exists = MemInfo::query()
                ->where('email', $email)
                ->lockForUpdate()
                ->exists();

            if ($exists) {
                throw new \RuntimeException('이미 가입된 아이디 입니다. 다른 아이디로 진행해 주세요.');
            }

            $now = Carbon::now()->format('Y-m-d H:i:s');
            $notnull = "1000-01-01 00:00:00";

            $mem = new MemInfo();
            $mem->email = $email;
            $mem->name = (string)($data['name'] ?? '');
            $mem->pv_sns = (string)($data['pv_sns'] ?? 'self');

            $promotion = !empty($data['promotion']) ? 'y' : 'n';
            $mem->rcv_email = $promotion;
            $mem->rcv_sms = $promotion;
            $mem->rcv_push = $promotion;

            $mem->dt_reg = $now;
            $mem->dt_login = $now;

            $mem->dt_rcv_email = $now;
            $mem->dt_rcv_sms = $now;
            $mem->dt_rcv_push = $now;
            $mem->dt_stat_1 = $now;
            $mem->dt_stat_2 = $now;
            $mem->dt_stat_3 = $now;
            $mem->dt_stat_4 = $now;
            $mem->dt_stat_5 = $now;

            $mem->dt_mod = $notnull;
            $mem->dt_vact = $notnull;
            $mem->dt_dor = $notnull;
            $mem->dt_ret_dor = $notnull;
            $mem->dt_req_out = "1000-01-01";
            $mem->dt_out = $notnull;

            $mem->ip_reg = (string)($data['ip_reg'] ?? request()->ip());

            // 국가/본인인증 값들
            $mem->country_code = (string)($data['country_code'] ?? '');
            $mem->country_name = (string)($data['country_name'] ?? '');
            $mem->birth = (string)($data['birth'] ?? '0000-00-00');
            $mem->cell_corp = (string)($data['cell_corp'] ?? 'n');

            // 휴대폰 암호화 (빈값이면 빈값)
            $rawPhone = (string)($data['cell_phone'] ?? '');
            if ($rawPhone !== '') {
                /** @var CiSeedCrypto $seed */
                $seed = app(CiSeedCrypto::class);
                $mem->cell_phone = (string)$seed->encrypt($rawPhone);
            } else {
                $mem->cell_phone = '';
            }

            $mem->native = (string)($data['native'] ?? 'n');
            $mem->ci = $data['ci'] ?? null;
            $mem->ci_v = (string)($data['ci_v'] ?? '');
            $mem->di = $data['di'] ?? null;
            $mem->gender = (string)($data['gender'] ?? 'n');

            // 1969년 이전 출생 접근금지(stat_3=3)
            $birthY = (int)substr((string)$mem->birth, 0, 4);
            if ($birthY > 0 && $birthY <= 1969) {
                $mem->stat_3 = '3';
            }

            $mem->save();

            return $mem;
        });
    }

    public function updateLastLogin(int $memNo): void
    {
        MemInfo::query()
            ->whereKey($memNo)
            ->update([
                'dt_login' => Carbon::now()->format('Y-m-d H:i:s'),
                'login_fail_cnt' => 0,
                'dt_mod' => Carbon::now()->format('Y-m-d H:i:s'),
            ]);
    }

    public function incrementLoginFail(int $memNo): void
    {
        MemInfo::query()
            ->whereKey($memNo)
            ->update([
                'login_fail_cnt' => DB::raw('login_fail_cnt + 1'),
                'dt_mod' => Carbon::now()->format('Y-m-d H:i:s'),
            ]);
    }

    private function dt6(): string
    {
        return Carbon::now()->format('Y-m-d H:i:s.u');
    }

    private function ip4c(string $ip): string
    {
        $oct = explode('.', $ip);
        if (count($oct) >= 3) {
            return $oct[0].'.'.$oct[1].'.'.$oct[2];
        }
        return $ip;
    }

    private function parseUa(string $ua): array
    {
        $platform = '';
        if (stripos($ua, 'Windows') !== false) $platform = 'Windows';
        elseif (stripos($ua, 'Mac OS X') !== false) $platform = 'macOS';
        elseif (stripos($ua, 'Android') !== false) $platform = 'Android';
        elseif (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPad') !== false) $platform = 'iOS';
        elseif (stripos($ua, 'Linux') !== false) $platform = 'Linux';

        $browser = 'Unknown';
        $version = '';
        $candidates = [
            'Edg/' => 'Edge',
            'Chrome/' => 'Chrome',
            'Firefox/' => 'Firefox',
            'Safari/' => 'Safari',
        ];

        foreach ($candidates as $needle => $name) {
            $pos = stripos($ua, $needle);
            if ($pos !== false) {
                $browser = $name;
                $sub = substr($ua, $pos + strlen($needle));
                $version = preg_split('/[^0-9\.]/', $sub)[0] ?? '';
                // Safari는 Chrome UA에도 같이 끼므로 Chrome 우선순위를 위에서 처리
                break;
            }
        }

        return [$platform, trim($browser), trim($version)];
    }

    /**
     * mem_auth 기반 레벨 계산 (CI3 get_mem_level 이식)
     */
    private function getMemLevel(int $memNo): array
    {
        $rows = DB::table('mem_auth')
            ->select(['auth_type','auth_state'])
            ->where('mem_no', $memNo)
            ->where('auth_state', 'Y')
            ->limit(50)
            ->get();

        $state = ['email'=>false,'cell'=>false,'account'=>false,'otp'=>false,'ars'=>false];

        foreach ($rows as $r) {
            $t = strtolower((string)$r->auth_type);
            if (array_key_exists($t, $state)) $state[$t] = true;
        }

        $level = 0;
        if ($state['email']) $level = 1;
        if ($level === 1 && $state['cell']) $level = 2;
        if ($level === 2 && $state['account']) $level = 3;
        if ($level === 3 && $state['otp']) $level = 4;
        if ($level === 2 && $state['ars']) $level = 5;

        return ['level'=>$level, 'auth_state'=>$state];
    }

    /**
     * 연도별 로그인 테이블 자동 생성 (B 선택)
     * - mem_login_recent 스키마를 그대로 복제
     */
    private function ensureLoginYearlyTable(int $year): string
    {
        $year = (int)$year;
        if ($year < 2000 || $year > 2100) {
            // 안전장치
            return 'mem_login_recent';
        }

        $table = "mem_login_{$year}";

        // DB마다 동작이 달라서 가장 단순하고 확실한 DDL로 처리
        // CREATE TABLE IF NOT EXISTS mem_login_YYYY LIKE mem_login_recent
        DB::statement("CREATE TABLE IF NOT EXISTS `{$table}` LIKE `mem_login_recent`");

        return $table;
    }

    private function insertLoginLog(string $table, array $d): void
    {
        DB::statement(
            "INSERT INTO `{$table}`
             SET mem_no=?,
                 sf=?,
                 conn=?,
                 ip4_aton=inet_aton(?),
                 ip4=?,
                 ip4_c=SUBSTRING_INDEX(?,'.',3),
                 dt_reg=?,
                 platform=?,
                 browser=?,
                 pattern=?,
                 error_code=?",
            [
                $d['mem_no'],
                $d['sf'],
                $d['conn'],
                $d['ip4'],
                $d['ip4'],
                $d['ip4'],
                $d['dt_reg'],
                $d['platform'],
                $d['browser'],
                $d['pattern'],
                $d['error_code'],
            ]
        );
    }


    public function attemptLegacyLogin(array $in): array
    {
        $email = strtolower(trim((string)($in['email'] ?? '')));
        $pw    = (string)($in['password'] ?? '');
        $ip    = (string)($in['ip'] ?? request()->ip());
        $ua    = (string)($in['ua'] ?? '');
        $returnUrl = (string)($in['return_url'] ?? '/');

        if ($email === '' || $pw === '') {
            return ['ok'=>false, 'message'=>'아이디 혹은 비밀번호가 일치하지 않습니다.'];
        }

        $dtNow6 = $this->dt6();
        $dtY = (int)substr($dtNow6, 0, 4);

        // UA 파싱
        [$platform, $browser, $version] = $this->parseUa($ua);
        $browserFull = trim($browser.' '.$version);

        //$yearTable = $this->ensureLoginYearlyTable((int)$dtY);


        return DB::transaction(function () use ($email, $pw, $ip, $ua, $returnUrl, $dtNow6, $dtY, $platform, $browserFull) {
            $yearTable = "mem_login_".(int)$dtY;

            /** @var MemInfo|null $mem */
            $mem = MemInfo::query()
                ->select([
                    'mem_no','email','name','cell_phone','cell_corp',
                    'dt_login','dt_reg','login_fail_cnt',
                    'pv_sns',
                    'stat_1','stat_2','stat_3','stat_4','stat_5',
                    'native','country_code'
                ])
                ->where('email', $email)
                ->lockForUpdate()
                ->first();

            // 아이디 없음 -> mem_no가 없으니 fail_count/log 저장 불가. 메시지만 통일.
            if (!$mem) {
                return ['ok'=>false, 'message'=>'아이디 혹은 비밀번호가 일치하지 않습니다.1'];
            }

            // stat_3 차단 로직 (CI3 id_exists 반영)
            if ((string)$mem->stat_3 === '3') {
                return ['ok'=>false, 'message'=>"접근금지 계정입니다.\n\n고객센터 1833-4856 로 문의 하세요"];
            }
            if ((string)$mem->stat_3 === '4') {
                return ['ok'=>false, 'message'=>'아이디 혹은 비밀번호가 일치하지 않습니다.2'];
            }
            if ((string)$mem->stat_3 === '5') {
                return ['ok'=>false, 'message'=>'아이디 혹은 비밀번호가 일치하지 않습니다.3'];
            }

            // 휴면(stat_3=6) 처리: 지금은 테이블 저장 + 안내까지만 (메일 연결은 다음 단계에서)
            if ((string)$mem->stat_3 === '6') {
                // TODO: mem_dormancy insert + authnum 생성 + 메일 발송 연결
                return ['ok'=>false, 'message'=>'회원님 계정은 휴면계정입니다. 이메일 인증 후 이용 가능합니다.4'];
            }

            // mem_st_ring 비번 로드
            $ring = DB::table('mem_st_ring')->where('mem_no', $mem->mem_no)->first();
            if (!$ring || empty($ring->str_0)) {
                $reason = config('legacy.login_reason.L_NOT_EXISTS_PASS');
                // 실패 카운트 + 실패 로그
                $this->incrementLoginFail((int)$mem->mem_no);

                $log = [
                    'mem_no' => (int)$mem->mem_no,
                    'sf' => 'f',
                    'conn' => '1',
                    'ip4' => $ip,
                    'ip4_c' => $this->ip4c($ip),
                    'dt_reg' => $dtNow6,
                    'platform' => $platform,
                    'browser' => $browserFull,
                    'pattern' => 'self',
                    'error_code' => $reason,
                ];


                $this->insertLoginLog('mem_login_recent', $log);
                 $this->insertLoginLog($yearTable, $log);

                return ['ok'=>false, 'message'=>'아이디 혹은 비밀번호가 일치하지 않습니다.5'];
            }

            // 비번 검증 (PASS_SET=0)
            $try = CiPassword::make($pw, 0);
            $dbPass = (string)$ring->str_0;

            if ($try === '' || strcmp($try, $dbPass) !== 0) {
                $reason = config('legacy.login_reason.L_INCORRECT_PASS');
                $failCnt = (int)$mem->login_fail_cnt;

                // 5회 실패 안내(>=4면 이번이 5회)
                if ($failCnt >= 4) {
                    $reason = config('legacy.login_reason.L_LOGIN_FAIL');
                }

                // 실패 카운트 + 실패 로그
                $this->incrementLoginFail((int)$mem->mem_no);

                $log = [
                    'mem_no' => (int)$mem->mem_no,
                    'sf' => 'f',
                    'conn' => '1',
                    'ip4' => $ip,
                    'ip4_c' => $this->ip4c($ip),
                    'dt_reg' => $dtNow6,
                    'platform' => $platform,
                    'browser' => $browserFull,
                    'pattern' => 'self',
                    'error_code' => $reason,
                ];

                $this->insertLoginLog('mem_login_recent', $log);
                $this->insertLoginLog($yearTable, $log);

                if ($failCnt >= 4) {
                    return ['ok'=>false, 'message'=>"비밀번호 입력 5회이상 실패 하셨습니다.\n 비밀번호찾기 후 이용 바랍니다."];
                }

                return ['ok'=>false, 'message'=>"비밀번호가 일치하지 않습니다.\n비밀번호 실패횟수 : ".($failCnt+1)."\n5회 이상 실패시 인증을 다시받아야 합니다."];
            }

            // 레벨 체크 (email 인증 필수)
            $levelInfo = $this->getMemLevel((int)$mem->mem_no);
            if (($levelInfo['level'] ?? 0) < 1 || empty($levelInfo['auth_state']['email'])) {
                return [
                    'ok' => false,
                    'reason' => 'email_unverified',
                    'email' => (string)$mem->email,
                    'mem_no' => (int)$mem->mem_no,
                    'message' => '이메일 인증이 필요합니다.',
                ];
            }

            // 로그인 차단 IP 대역 체크
            $ip4c = $this->ip4c($ip);
            $blocked = DB::table('filter_login_ip_reject')
                ->where('mem_no', $mem->mem_no)
                ->where('ip4_c', $ip4c)
                ->exists();

            if ($blocked) {
                return ['ok'=>false, 'message'=>"회원님의 설정에 의해 접속이 차단되었습니다.6"];
            }

            // 최근 로그인 업데이트(성공 시 fail_count reset)
            $this->updateLastLogin((int)$mem->mem_no);

            // 성공 로그 저장(최근 + 연도별)
            $log = [
                'mem_no' => (int)$mem->mem_no,
                'sf' => 's',
                'conn' => '1',
                'ip4' => $ip,
                'ip4_c' => $ip4c,
                'dt_reg' => $dtNow6,
                'platform' => $platform,
                'browser' => $browserFull,
                'pattern' => 'self',
                'error_code' => '',
            ];

            $this->insertLoginLog('mem_login_recent', $log);
            $this->insertLoginLog($yearTable, $log);

            // 첫 로그인 여부
            $login1st = 'n';
            if ((string)$mem->dt_login === (string)$mem->dt_reg) {
                $login1st = 'y';
            }

            // ✅ 세션 payload (CI3 키 유지)
            $session = [
                '_login_'        => true,
                '_mid'           => (string)$mem->email,
                '_mno'           => (int)$mem->mem_no,
                '_mname'         => (string)$mem->name,
                '_mstat_1'       => (string)$mem->stat_1,
                '_mstat_2'       => (string)$mem->stat_2,
                '_mstat_3'       => (string)$mem->stat_3,
                '_mstat_4'       => (string)$mem->stat_4,
                '_mstat_5'       => (string)$mem->stat_5,
                '_mcell'         => (string)$mem->cell_phone,
                '_mpv_sns'       => (string)$mem->pv_sns,
                '_mnative'       => (string)$mem->native,
                '_mcountry_code' => (string)$mem->country_code,
                '_ip'            => $ip,
                '_login_1st'     => $login1st,
                '_dt_reg'        => (string)$mem->dt_reg,
                'auth_ars'       => !empty($levelInfo['auth_state']['ars']) ? 'Y' : 'N',
            ];

            return [
                'ok' => true,
                'session' => $session,
                'redirect' => $returnUrl ?: '/',
            ];
        });
    }

    public function getReceive(int $memNo): array
    {
        $mem = MemInfo::query()->whereKey($memNo)->first();

        // ✅ 출금계좌 인증정보 (있으면 1건)
        $outAccount = DB::table('mem_account')
            ->select(['bank_name', 'bank_act_num', 'bank_act_name', 'act_date'])
            ->where('mem_no', $memNo)
            ->where('act_type', 'out')
            ->where('act_state', '3')
            ->orderByDesc('act_date')
            ->first();

        if (!$mem) {
            return [
                'rcv_email' => 'n',
                'rcv_sms'   => 'n',
                'rcv_push'  => null,
                'out_account' => $outAccount ? [
                    'bank_name'    => (string)($outAccount->bank_name ?? ''),
                    'bank_act_num' => (string)($outAccount->bank_act_num ?? ''),
                    'bank_act_name'=> (string)($outAccount->bank_act_name ?? ''),
                    'act_date'     => (string)($outAccount->act_date ?? ''),
                ] : null,
            ];
        }

        return [
            'rcv_email' => (string)($mem->rcv_email ?? 'n'),
            'rcv_sms'   => (string)($mem->rcv_sms ?? 'n'),
            'rcv_push'  => $mem->rcv_push !== null ? (string)$mem->rcv_push : null,

            // ✅ 추가
            'out_account' => $outAccount ? [
                'bank_name'    => (string)($outAccount->bank_name ?? ''),
                'bank_act_num' => (string)($outAccount->bank_act_num ?? ''),
                'bank_act_name'=> (string)($outAccount->bank_act_name ?? ''),
                'act_date'     => (string)($outAccount->act_date ?? ''),
            ] : null,
        ];
    }


    /*회원정보 수신동의 정보 저장*/
    public function setReceiveSelective(int $memNo, string $rcvEmail, string $rcvSms): array
    {
        $rcvEmail = ($rcvEmail === 'y') ? 'y' : 'n';
        $rcvSms   = ($rcvSms === 'y') ? 'y' : 'n';

        return DB::transaction(function () use ($memNo, $rcvEmail, $rcvSms) {
            /** @var MemInfo $mem */
            $mem = MemInfo::query()->whereKey($memNo)->lockForUpdate()->firstOrFail();

            $beforeEmail = (string) ($mem->rcv_email ?? 'n');
            $beforeSms   = (string) ($mem->rcv_sms ?? 'n');

            $changedEmail = ($beforeEmail !== $rcvEmail);
            $changedSms   = ($beforeSms !== $rcvSms);

            if (!$changedEmail && !$changedSms) {
                return [
                    'changed' => [],
                    'message' => '변경된 내용이 없습니다.',
                ];
            }

            $now = Carbon::now()->format('Y-m-d H:i:s');

            if ($changedEmail) {
                $mem->rcv_email = $rcvEmail;
                $mem->dt_rcv_email = $now;
            }

            if ($changedSms) {
                $mem->rcv_sms = $rcvSms;
                $mem->dt_rcv_sms = $now;
            }

            // 공통 수정일은 변경이 있을 때만
            $mem->dt_mod = $now;
            $mem->save();

            $changed = [];
            if ($changedEmail) $changed[] = 'email';
            if ($changedSms) $changed[] = 'sms';

            $label = [];
            if ($changedEmail) $label[] = '이메일';
            if ($changedSms) $label[] = 'SMS';

            return [
                'changed' => $changed,
                'message' => implode('·', $label) . ' 수신 동의 설정이 저장되었습니다.',
            ];
        });
    }

    //회원 탈퇴 최근 구매내역 확인
    public function validateWithdraw(int $memNo): array
    {
        if ($memNo <= 0) {
            return ['ok' => false, 'message' => '로그인 정보가 올바르지 않습니다.'];
        }

        // ✅ 최근 7일 이내 구매내역(stat_pay p/t) 있으면 불가
        $from = Carbon::today()->subDays(7)->startOfDay();

        $cnt = (int) DB::table('pin_order')
        ->where('mem_no', $memNo)
            ->whereIn('stat_pay', ['p','t'])
            ->where('dt_stat_pay', '>=', $from->toDateTimeString())
            ->count();

        if ($cnt > 0) {
            return [
                'ok' => false,
                'message' => '죄송합니다. 최근 7일 이내 구매내역이 있는 경우 즉시 탈퇴가 불가합니다. 고객센터로 탈퇴 접수를 해주시기 바랍니다',
            ];
        }

        return ['ok' => true];
    }

    //회원탈퇴 진행
    public function withdrawMember(int $memNo): array
    {
        $v = $this->validateWithdraw($memNo);
        if (!($v['ok'] ?? false)) return $v;

        $now = Carbon::now();
        $dtReqOut = $now->copy()->addDays(90)->toDateString(); // Y-m-d

        DB::transaction(function () use ($memNo, $now, $dtReqOut) {

            // 1) mem_info 비식별/초기화 + 탈퇴 처리
            DB::table('mem_info')
                ->where('mem_no', $memNo)
                ->update([
                    'name'          => '',
                    'name_first'    => '',
                    'name_mid'      => '',
                    'name_last'     => '',
                    'birth'         => '1900-01-01',
                    'gender'        => '',
                    'native'        => '',
                    'cell_corp'     => '',
                    'cell_phone'    => '',
                    'ci'            => '',
                    'bank_code'     => '',
                    'bank_name'     => '',
                    'bank_act_num'  => '',
                    'bank_vact_num' => '',

                    'dt_req_out'    => $dtReqOut,
                    'dt_out'        => $now->toDateTimeString(),
                    'stat_3'        => '4',
                    'dt_mod'        => $now->toDateTimeString(),
                ]);

            // 2) mem_account 초기화
            DB::table('mem_account')
                ->where('mem_no', $memNo)
                ->update([
                    'bank_code'     => '',
                    'bank_name'     => '',
                    'bank_act_name' => '',
                    'bank_act_num'  => '',
                ]);

            // 3) mem_address 초기화
            DB::table('mem_address')
                ->where('mem_no', $memNo)
                ->update([
                    'shipping'      => '',
                    'zipNo'         => '',
                    'roadAddrPart1' => '',
                    'jibunAddr'     => '',
                    'addrDetail'    => '',
                ]);

            // 4) mem_auth 인증 해제
            DB::table('mem_auth')
                ->where('mem_no', $memNo)
                ->update([
                    'auth_state' => 'N',
                ]);

            // 5) mem_st_ring 비번/2차 비번 제거
            DB::table('mem_st_ring')
                ->where('mem_no', $memNo)
                ->update([
                    'str_0'        => '',
                    'str_1'        => '',
                    'str_2'        => '',
                    'dt_reg'       => $now->toDateTimeString(),

                    'passwd2'      => '',
                    'passwd2_reg'  => $now->toDateTimeString(),
                ]);
        });

        return ['ok' => true, 'message' => '회원탈퇴가 완료되었습니다.'];
    }
}
