<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Auth\CheckNisRequest;
use App\Http\Requests\Api\Auth\LoginWithPinRequest;
use App\Http\Requests\Api\Auth\RegisterStudentRequest;
use App\Http\Requests\Api\Auth\SetupPinRequest;
use App\Models\Auth\MobileAccessToken;
use App\Models\Datmas\Indentitas;
use App\Models\Datmas\Siswa;
use App\Services\Auth\MobileTokenService;
use App\Services\Auth\MobileStudentResolver;
use App\Services\Auth\RegistrationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class MobileAuthController extends Controller
{
    public function __construct(
        protected MobileTokenService $tokenService,
        protected MobileStudentResolver $studentResolver,
        protected RegistrationService $registrationService,
    ) {
    }

    public function checkNis(CheckNisRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $siswa = $this->studentResolver->findByNis($validated['nis']);

        if (!$siswa) {
            throw ValidationException::withMessages([
                'nis' => ['Data siswa tidak ditemukan.'],
            ]);
        }

        $indentitas = $siswa->indentitas;

        return response()->json([
            'success' => true,
            'message' => $this->checkNisMessage($siswa, $indentitas),
            'data' => [
                'account_id' => $this->studentResolver->accountId($siswa),
                'nouid' => $indentitas?->nouid,
                'nis' => $siswa->nis,
                'nama' => $siswa->namlen,
                'kelas' => $this->studentClass($siswa),
                'telepon' => $siswa->tel,
                'has_pin' => $siswa->has_pin,
                'identity_available' => (bool) $indentitas,
                'registrasi' => $this->registrationMeta($indentitas, $siswa),
            ],
        ]);
    }

    public function register(RegisterStudentRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $requestedSiswa = $this->studentResolver->findByNis($validated['nis']);

        if ($requestedSiswa?->has_pin) {
            $indentitas = $requestedSiswa->indentitas;

            return response()->json([
                'success' => false,
                'message' => $this->checkNisMessage($requestedSiswa, $indentitas),
                'data' => [
                    'account_id' => $this->studentResolver->accountId($requestedSiswa),
                    'nouid' => $indentitas?->nouid,
                    'nis' => $requestedSiswa->nis,
                    'nama' => $requestedSiswa->namlen,
                    'kelas' => $this->studentClass($requestedSiswa),
                    'telepon' => $requestedSiswa->tel,
                    'has_pin' => true,
                    'identity_available' => (bool) $indentitas,
                    'registrasi' => $this->registrationMeta($indentitas, $requestedSiswa),
                ],
            ], 409);
        }

        if (! $requestedSiswa) {
            throw ValidationException::withMessages([
                'nis' => ['Data siswa tidak ditemukan.'],
            ]);
        }

        $indentitas = $requestedSiswa->indentitas;
        $registration = $this->studentResolver->registration($requestedSiswa);
        $accountId = $this->studentResolver->accountId($requestedSiswa);

        if ($this->studentResolver->isBlocked($requestedSiswa)) {
            return response()->json([
                'success' => false,
                'message' => 'Akun ini diblokir dan tidak dapat melakukan registrasi.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $requestedSiswa),
                ],
            ], 423);
        }

        if ($requestedSiswa->has_pin) {
            return response()->json([
                'success' => false,
                'message' => 'NIS ini sudah membuat akun. Silakan masuk ke halaman login.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $requestedSiswa),
                ],
            ], 409);
        }

        if ($registration?->sta === 0) {
            return response()->json([
                'success' => false,
                'message' => 'Pendaftaran masih dalam proses verifikasi.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $requestedSiswa),
                ],
            ], 409);
        }

        if ($registration?->sta === 1) {
            return response()->json([
                'success' => false,
                'message' => 'Pendaftaran sudah disetujui. Lanjutkan ke pembuatan PIN.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $requestedSiswa),
                ],
            ], 409);
        }

        $documentFile = $request->file('ktpFile')
            ?? $request->file('ktp_file')
            ?? $request->file('pasporFile')
            ?? $request->file('paspor_file');

        $result = DB::connection('mai4')->transaction(function () use ($validated, $accountId, $requestedSiswa, $documentFile, $request) {
            return $this->registrationService->store(
                $accountId,
                [...$validated, 'nis' => $requestedSiswa->nis],
                $documentFile,
                0,
                $request->ip(),
                $request->userAgent(),
            );
        });

        return response()->json([
            'success' => true,
            'message' => 'Pendaftaran berhasil dikirim dan sedang diverifikasi.',
            'data' => [
                'account_id' => $accountId,
                'nouid' => $indentitas?->nouid,
                'nis' => $requestedSiswa->nis,
                'nama' => $requestedSiswa->namlen,
                'registrasi' => [
                    'status_code' => $result['registration']->sta,
                    'status' => 'pending',
                    'status_label' => 'Menunggu verifikasi',
                    'can_register' => false,
                    'can_setup_pin' => false,
                    'has_pin' => $requestedSiswa->has_pin,
                ],
            ],
        ], 201);
    }

    public function setupPin(SetupPinRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $siswa = $this->studentResolver->findByNis($validated['nis']);

        if (! $siswa) {
            throw ValidationException::withMessages([
                'nis' => ['Data siswa tidak ditemukan.'],
            ]);
        }

        $indentitas = $siswa->indentitas;
        $registration = $this->studentResolver->registration($siswa);
        $accountId = $this->studentResolver->accountId($siswa);

        if ($siswa->has_pin) {
            return response()->json([
                'success' => false,
                'message' => 'NIS ini sudah membuat akun. Silakan masuk ke halaman login.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $siswa),
                ],
            ], 409);
        }

        if (! $registration || $registration->sta !== 1) {
            return response()->json([
                'success' => false,
                'message' => 'Registrasi belum disetujui. PIN belum bisa dibuat.',
                'data' => [
                    'registrasi' => $this->registrationMeta($indentitas, $siswa),
                ],
            ], 409);
        }

        $phone = $validated['phone'] ?? $registration->tel ?? $siswa->tel;

        if (!$phone) {
            throw ValidationException::withMessages([
                'phone' => ['Nomor telepon belum tersedia untuk akun ini.'],
            ]);
        }

        [$token, $plainTextToken, $siswa] = DB::transaction(function () use ($siswa, $indentitas, $registration, $validated, $accountId, $request) {
            $phone = $validated['phone'] ?? $registration->tel ?? $siswa->tel;
            $siswa->update([
                'pin' => $validated['pin'],
                'tel' => formatPhoneNumber((string) $phone),
            ]);

            if ($indentitas) {
                Indentitas::query()
                    ->where('nouid', $indentitas->nouid)
                    ->update(['sta' => 0]);
            }

            [$token, $plainTextToken] = $this->tokenService->issueToken(
                $siswa,
                $accountId,
                $validated['device_name'],
                $request->ip(),
                $request->userAgent(),
            );

            return [$token, $plainTextToken, $siswa->fresh()];
        });

        return response()->json([
            'success' => true,
            'message' => 'PIN berhasil dibuat.',
            'data' => [
                'token_type' => 'Bearer',
                'access_token' => $plainTextToken,
                'expires_at' => $token->expires_at?->toIso8601String(),
                'active_student' => $this->transformUser($siswa, $accountId),
                'students' => $this->transformStudentList(collect([$siswa])),
            ],
        ], 201);
    }

    public function login(LoginWithPinRequest $request): JsonResponse
    {
        [, $siswa, $accountId, $allStudents] = $request->authenticateStudent();

        [$token, $plainTextToken] = $this->tokenService->issueToken(
            $siswa,
            $accountId,
            $request->string('device_name')->toString(),
            $request->ip(),
            $request->userAgent(),
        );

        return response()->json([
            'success' => true,
            'message' => 'Login berhasil.',
            'data' => [
                'token_type' => 'Bearer',
                'access_token' => $plainTextToken,
                'expires_at' => $token->expires_at?->toIso8601String(),
                'active_student' => $this->transformUser($siswa, $accountId),
                'students' => $this->transformStudentList($allStudents),
            ],
        ]);
    }

    public function me(Request $request): JsonResponse
    {
        /** @var Siswa $siswa */
        $siswa = $request->attributes->get('auth_siswa');
        $accountId = $request->attributes->get('auth_account_id');

        // Muat semua siswa yang terhubung ke nomor HP yang sama
        $phone = $siswa->tel;
        $allStudents = collect([$siswa]);
        if ($phone) {
            $localNumber = preg_replace('/^62/', '', $phone);
            $phoneCandidates = array_values(array_unique(array_filter([
                $phone,
                '0' . $localNumber,
                $localNumber,
                '+' . $phone,
            ])));
            $allStudents = $this->studentResolver->findByPhoneCandidates($phoneCandidates)
                ->filter(fn (Siswa $s) => $s->has_pin);
        }

        return response()->json([
            'success' => true,
            'message' => 'Profil berhasil diambil.',
            'data' => [
                'active_student' => $this->transformUser($siswa, $accountId),
                'students' => $this->transformStudentList($allStudents),
            ],
        ]);
    }

    public function logout(Request $request): JsonResponse
    {
        /** @var MobileAccessToken|null $token */
        $token = $request->attributes->get('auth_mobile_token');

        if ($token) {
            $token->delete();
        }

        return response()->json([
            'success' => true,
            'message' => 'Logout berhasil.',
        ]);
    }

    protected function transformUser(Siswa $siswa, string $accountId): array
    {
        $siswa->loadMissing(['kelsis', 'indentitas']);

        return [
            'account_id' => $accountId,
            'nouid' => $siswa->indentitas?->nouid,
            'nis' => $siswa->nis,
            'nama' => $siswa->namlen,
            'kelas' => $this->studentClass($siswa),
            'telepon' => $siswa->tel,
            'has_pin' => $siswa->has_pin,
        ];
    }

    /**
     * Transform koleksi siswa menjadi array ringkas untuk daftar pemilih anak.
     */
    protected function transformStudentList(\Illuminate\Support\Collection $students): array
    {
        return $students->values()->map(function (Siswa $siswa) {
            $siswa->loadMissing(['kelsis', 'indentitas']);
            return [
                'nis' => $siswa->nis,
                'nama' => $siswa->namlen,
                'kelas' => $this->studentClass($siswa),
                'nouid' => $siswa->indentitas?->nouid,
            ];
        })->all();
    }

    protected function checkNisMessage(Siswa $siswa, ?Indentitas $indentitas): string
    {
        if ($this->studentResolver->isBlocked($siswa)) {
            return 'Akun ini diblokir dan tidak dapat melakukan registrasi.';
        }

        if ($siswa->has_pin) {
            return 'NIS ini sudah membuat akun. Silakan masuk ke halaman login.';
        }

        return 'NIS ditemukan.';
    }

    protected function registrationMeta(?Indentitas $indentitas, ?Siswa $siswa = null): array
    {
        if (!$indentitas) {
            $hasPin = (bool) $siswa?->has_pin;
            $registration = $siswa ? $this->studentResolver->registration($siswa) : null;
            $statusCode = $registration?->sta;
            $status = match (true) {
                $statusCode === -2 => 'blocked',
                $hasPin => 'account_exists',
                $statusCode === -1 => 'rejected',
                $statusCode === 0 => 'pending',
                $statusCode === 1 && ! $hasPin => 'approved',
                default => 'unregistered',
            };

            $label = match ($status) {
                'blocked' => 'Diblokir',
                'rejected' => 'Ditolak',
                'pending' => 'Menunggu verifikasi',
                'approved' => 'Disetujui, siap buat PIN',
                'account_exists' => 'Akun sudah dibuat',
                default => 'Belum daftar',
            };

            return [
                'status_code' => $statusCode,
                'status' => $status,
                'status_label' => $label,
                'can_register' => !$hasPin && in_array($statusCode, [null, -1], true),
                'can_setup_pin' => $statusCode === 1 && !$hasPin,
                'can_login' => $status === 'account_exists',
                'has_pin' => $hasPin,
                'identity_available' => false,
            ];
        }

        $statusCode = $siswa
            ? $this->studentResolver->registration($siswa)?->sta
            : $indentitas->registrasi?->sta;
        $hasPin = (bool) ($indentitas->siswa?->has_pin ?? $siswa?->has_pin);

        $status = match (true) {
            !$indentitas->active, $statusCode === -2 => 'blocked',
            $hasPin => 'account_exists',
            $statusCode === -1 => 'rejected',
            $statusCode === 0 => 'pending',
            $statusCode === 1 && !$hasPin => 'approved',
            default => 'unregistered',
        };

        $label = match ($status) {
            'blocked' => 'Diblokir',
            'rejected' => 'Ditolak',
            'pending' => 'Menunggu verifikasi',
            'approved' => 'Disetujui, siap buat PIN',
            'active' => 'Aktif',
            'account_exists' => 'Akun sudah dibuat',
            default => 'Belum daftar',
        };

        return [
            'status_code' => $statusCode,
            'status' => $status,
            'status_label' => $label,
            'can_register' => !$hasPin && in_array($statusCode, [null, -1], true),
            'can_setup_pin' => $statusCode === 1 && !$hasPin,
            'can_login' => $status === 'account_exists',
            'has_pin' => $hasPin,
            'identity_available' => true,
        ];
    }

    protected function studentClass(Siswa $siswa): ?string
    {
        return data_get($siswa->getRelationValue('kelsis'), 'kel')
            ?? $siswa->getRawOriginal('kel');
    }
}
