<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Auth\RegisterLinkedStudentRequest;
use App\Models\Datmas\Siswa;
use App\Models\Saving\Tregistrasi;
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\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

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

    /**
     * GET /v1/mobile/students
     * Daftar siswa aktif + pending registrasi yang terhubung ke nomor HP pemilik token.
     */
    public function index(Request $request): JsonResponse
    {
        /** @var Siswa $tokenOwner */
        $tokenOwner = $request->attributes->get('auth_siswa');

        $students       = $this->getLinkedStudents($tokenOwner);
        $pendingRequests = $this->getPendingRequests($tokenOwner);

        return response()->json([
            'success' => true,
            'message' => 'Daftar siswa berhasil diambil.',
            'data' => [
                'students'        => $students->values()->map(fn (Siswa $s) => $this->transformStudent($s))->all(),
                'pending_requests' => $pendingRequests,
            ],
        ]);
    }

    /**
     * POST /v1/mobile/students/link
     * Alur A: Tautkan siswa yang sudah punya PIN via NIS + PIN (instant).
     */
    public function link(Request $request): JsonResponse
    {
        $request->validate([
            'nis' => 'required|string',
            'pin' => 'required|digits:6|numeric',
        ]);

        /** @var Siswa $tokenOwner */
        $tokenOwner = $request->attributes->get('auth_siswa');

        $nis = $request->string('nis')->toString();
        $pin = $request->string('pin')->toString();

        $target = $this->studentResolver->findByNis($nis);

        if (!$target) {
            throw ValidationException::withMessages([
                'nis' => ['Siswa dengan NIS tersebut tidak ditemukan.'],
            ]);
        }

        if ($target->nis === $tokenOwner->nis) {
            throw ValidationException::withMessages([
                'nis' => ['Siswa ini sudah terhubung ke akun Anda.'],
            ]);
        }

        if (!$target->has_pin) {
            throw ValidationException::withMessages([
                'nis' => ['Siswa ini belum membuat PIN. Gunakan "Daftar Siswa Baru" untuk mendaftarkannya.'],
            ]);
        }

        if (!Hash::check($pin, $target->pin)) {
            throw ValidationException::withMessages([
                'pin' => ['PIN siswa tidak cocok.'],
            ]);
        }

        if ($this->isAlreadyLinked($tokenOwner->tel, $target->tel)) {
            throw ValidationException::withMessages([
                'nis' => ['Siswa ini sudah terhubung ke nomor HP Anda.'],
            ]);
        }

        $target->update(['tel' => $tokenOwner->tel]);

        $students = $this->getLinkedStudents($tokenOwner->fresh());

        return response()->json([
            'success' => true,
            'message' => "Siswa {$target->namlen} berhasil ditautkan.",
            'data' => [
                'linked_student'  => $this->transformStudent($target->fresh()),
                'students'        => $students->values()->map(fn (Siswa $s) => $this->transformStudent($s))->all(),
                'pending_requests' => $this->getPendingRequests($tokenOwner->fresh()),
            ],
        ], 201);
    }

    /**
     * POST /v1/mobile/students/register
     * Alur B: Daftarkan siswa baru (sama seperti registrasi normal) tapi:
     *   - Nomor HP otomatis dari token pemilik (tidak perlu input ulang)
     *   - Tidak butuh OTP
     *   - Status: pending di Tregistrasi (sta=0), tunggu approval admin
     */
    public function register(RegisterLinkedStudentRequest $request): JsonResponse
    {
        $validated = $request->validated();

        /** @var Siswa $tokenOwner */
        $tokenOwner = $request->attributes->get('auth_siswa');

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

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

        // Pastikan tidak mendaftarkan diri sendiri
        if ($target->nis === $tokenOwner->nis) {
            throw ValidationException::withMessages([
                'nis' => ['Tidak dapat mendaftarkan siswa yang sedang aktif.'],
            ]);
        }

        // Siswa yang sudah punya PIN harus gunakan Alur A (link)
        if ($target->has_pin) {
            throw ValidationException::withMessages([
                'nis' => ['Siswa ini sudah memiliki akun. Gunakan "Sudah Punya PIN" untuk menautkannya.'],
            ]);
        }

        // Cek sudah ada pending/approved registration
        $existingRegistration = $this->studentResolver->registration($target);
        if ($existingRegistration && in_array($existingRegistration->sta, [
            Tregistrasi::STATUS_PENDING,
            Tregistrasi::STATUS_ACCEPTED,
        ])) {
            return response()->json([
                'success' => false,
                'message' => 'Pendaftaran siswa ini sedang dalam proses. Silakan tunggu.',
                'data' => [
                    'sta'       => $existingRegistration->sta,
                    'sta_label' => $existingRegistration->sta === Tregistrasi::STATUS_PENDING
                        ? 'Menunggu Persetujuan'
                        : 'Disetujui',
                ],
            ], 409);
        }

        $accountId = $this->studentResolver->accountId($target);

        // Gunakan nomor HP pemilik token (bukan dari form)
        $validated['tel'] = $tokenOwner->tel;

        $result = DB::connection('mai4')->transaction(function () use ($validated, $accountId, $target, $request) {
            return $this->registrationService->store(
                $accountId,
                [...$validated, 'nis' => $target->nis],
                $request->file('ktpFile') ?? $request->file('ktp_file')
                    ?? $request->file('pasporFile') ?? $request->file('paspor_file'),
                0,
                $request->ip(),
                $request->userAgent(),
            );
        });

        return response()->json([
            'success' => true,
            'message' => "Pendaftaran {$target->namlen} berhasil dikirim. Menunggu persetujuan sekolah.",
            'data' => [
                'nis'       => $target->nis,
                'nama'      => $target->namlen,
                'sta'       => Tregistrasi::STATUS_PENDING,
                'sta_label' => 'Menunggu Persetujuan',
            ],
        ], 201);
    }

    /**
     * DELETE /v1/mobile/students/{nis}/unlink
     * Lepas tautan siswa aktif dari nomor HP ini.
     */
    public function unlink(Request $request, string $nis): JsonResponse
    {
        /** @var Siswa $tokenOwner */
        $tokenOwner = $request->attributes->get('auth_siswa');

        if ($nis === $tokenOwner->nis) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak dapat melepas tautan akun utama.',
            ], 422);
        }

        $target = $this->studentResolver->findSiblingByNis($nis, $tokenOwner);

        if (!$target) {
            return response()->json([
                'success' => false,
                'message' => 'Siswa tidak ditemukan atau tidak terhubung ke akun Anda.',
            ], 404);
        }

        $target->update(['tel' => null]);

        $students = $this->getLinkedStudents($tokenOwner->fresh());

        return response()->json([
            'success' => true,
            'message' => "Siswa {$target->namlen} berhasil dilepas.",
            'data' => [
                'students'        => $students->values()->map(fn (Siswa $s) => $this->transformStudent($s))->all(),
                'pending_requests' => $this->getPendingRequests($tokenOwner->fresh()),
            ],
        ]);
    }

    // ─── Helpers ─────────────────────────────────────────────────────────────

    protected function getLinkedStudents(Siswa $tokenOwner): \Illuminate\Database\Eloquent\Collection
    {
        $phone = $tokenOwner->tel;

        if (!$phone) {
            return collect([$tokenOwner]);
        }

        $localNumber = preg_replace('/^62/', '', $phone);
        $candidates = array_values(array_unique(array_filter([
            $phone,
            '0' . $localNumber,
            $localNumber,
            '+' . $phone,
        ])));

        return $this->studentResolver->findByPhoneCandidates($candidates)
            ->filter(fn (Siswa $s) => $s->has_pin);
    }

    /**
     * Ambil daftar registrasi pending yang nomor HP-nya cocok dengan pemilik token.
     */
    protected function getPendingRequests(Siswa $tokenOwner): array
    {
        $phone = $tokenOwner->tel;
        if (!$phone) return [];

        $localNumber = preg_replace('/^62/', '', $phone);
        $candidates = array_values(array_unique(array_filter([
            $phone,
            '0' . $localNumber,
            $localNumber,
            '+' . $phone,
        ])));

        // Ambil nouid semua siswa aktif (has_pin=true) yang terhubung ke nomor ini
        // Siswa->indentitas berjalan dalam connection yang sama — aman digunakan
        $activeStudents = $this->getLinkedStudents($tokenOwner);
        $activeStudents->loadMissing('indentitas');

        // Set nouid siswa aktif (untuk siswa yang punya Indentitas record)
        $activeNouidSet = $activeStudents
            ->map(fn(Siswa $s) => $s->indentitas?->nouid)
            ->filter()
            ->flip()
            ->toArray();

        // Set NIS siswa aktif (untuk siswa tanpa Indentitas — Tregistrasi.nouid = NIS mereka)
        $activeNisSet = $activeStudents
            ->pluck('nis')
            ->filter()
            ->flip()
            ->toArray();

        return Tregistrasi::whereIn('sta', [Tregistrasi::STATUS_PENDING, Tregistrasi::STATUS_ACCEPTED])
            ->whereIn('tel', $candidates)
            ->get()
            // Exclude jika nouid = nouid siswa aktif (dengan Indentitas)
            // ATAU nouid = NIS siswa aktif (untuk siswa tanpa Indentitas record)
            ->filter(fn(Tregistrasi $reg) =>
                !array_key_exists($reg->nouid, $activeNouidSet) &&
                !array_key_exists($reg->nouid, $activeNisSet)
            )
            ->map(function (Tregistrasi $reg) {
                // Load indentitas secara terpisah (menghindari cross-DB eager loading)
                $indentitas = \App\Models\Datmas\Indentitas::where('nouid', $reg->nouid)->first();
                $siswa      = $indentitas?->siswa;
                return [
                    'id'         => $reg->id,
                    'nis'        => $siswa?->nis ?? $reg->nouid,
                    'nouid'      => $reg->nouid,
                    'nama'       => $siswa?->namlen ?? $reg->nama,
                    'kelas'      => $siswa?->getRelationValue('kelsis')?->kel ?? null,
                    'sta'        => $reg->sta,
                    'sta_label'  => $reg->sta === Tregistrasi::STATUS_PENDING
                        ? 'Menunggu Persetujuan'
                        : 'Disetujui',
                    'created_at' => $reg->created_at?->toISOString(),
                ];
            })
            ->values()
            ->all();
    }

    protected function isAlreadyLinked(?string $phone1, ?string $phone2): bool
    {
        if (!$phone1 || !$phone2) return false;
        $normalize = fn (string $p) => preg_replace('/^(\+62|62|0)/', '', $p);
        return $normalize($phone1) === $normalize($phone2);
    }

    protected function transformStudent(Siswa $siswa): array
    {
        $siswa->loadMissing(['kelsis', 'indentitas']);
        return [
            'nis'   => $siswa->nis,
            'nama'  => $siswa->namlen,
            'kelas' => data_get($siswa->getRelationValue('kelsis'), 'kel') ?? $siswa->getRawOriginal('kel'),
            'nouid' => $siswa->indentitas?->nouid,
        ];
    }
}
