<?php

namespace App\Http\Controllers\Api;

use App\Enums\Status;
use App\Http\Controllers\Controller;
use App\Models\Admin\Tizin;
use App\Models\Admin\Tizinjenis;
use App\Models\Datmas\Siswa;
use App\Models\Saving\Timagable;
use App\Services\DataValidatorService;
use App\Services\IzinService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class MobileIzinController extends Controller
{
    public function __construct(
        protected IzinService $izinService,
        protected DataValidatorService $validator,
    ) {}

    public function jenis(Request $request): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $accountId = $this->authenticatedAccountId($request);

        return response()->json([
            'success' => true,
            'message' => 'Jenis izin berhasil diambil.',
            'data' => [
                'account_id' => $accountId,
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'jenis' => $this->izinService->getJenis()
                    ->map(fn(Tizinjenis $jenis) => $this->transformJenis($jenis))
                    ->values()
                    ->all(),
            ],
        ]);
    }

    public function index(Request $request): JsonResponse
    {
        return $this->history($request);
    }

    public function history(Request $request): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $accountId = $this->authenticatedAccountId($request);
        $izin = $this->izinQuery($siswa)->get();
        $riwayat = $izin->map(fn(Tizin $item) => $this->transformIzin($item))->values()->all();

        return response()->json([
            'success' => true,
            'message' => 'Riwayat izin berhasil diambil.',
            'data' => [
                'account_id' => $accountId,
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'summary' => $this->summarize($izin),
                'statuses' => $this->statuses(),
                'izin' => $riwayat,
                'riwayat' => $riwayat,
            ],
        ]);
    }

    public function store(Request $request): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $accountId = $this->authenticatedAccountId($request);
        $file = $this->uploadedDocument($request);
        $payload = $request->all();

        // Gunakan tsiswa.id (kolom numerik) sebagai idsis.
        // Validasi pakai exists:mai2.tsiswa,id sehingga sibling yang belum punya
        // tindentitas (belum daftar mobile mandiri) tetap bisa mengajukan izin.
        $payload['idsis'] = $siswa->getAttribute('id');

        if ($file) {
            $payload['dok'] = $file;
        }

        $validated = $this->validator->tizin($payload);

        $izin = $this->izinService->create($validated, $file);
        $izin = $this->izinQuery($siswa)->whereKey($izin->id)->firstOrFail();

        return response()->json([
            'success' => true,
            'message' => 'Izin berhasil diajukan.',
            'data' => [
                'account_id' => $accountId,
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'izin' => $this->transformIzin($izin),
            ],
        ], 201);
    }

    public function show(Request $request, int $izin): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $record = $this->izinQuery($siswa)->whereKey($izin)->first();

        if (! $record) {
            return $this->notFoundResponse();
        }

        return response()->json([
            'success' => true,
            'message' => 'Detail izin berhasil diambil.',
            'data' => [
                'account_id' => $this->authenticatedAccountId($request),
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'izin' => $this->transformIzin($record),
            ],
        ]);
    }

    public function status(Request $request, int $izin): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $record = $this->izinQuery($siswa)->whereKey($izin)->first();

        if (! $record) {
            return $this->notFoundResponse();
        }

        return response()->json([
            'success' => true,
            'message' => 'Status izin berhasil diambil.',
            'data' => [
                'account_id' => $this->authenticatedAccountId($request),
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'izin_id' => (int) $record->id,
                ...$this->statusPayload($record),
            ],
        ]);
    }

    public function cancel(Request $request, int $izin): JsonResponse
    {
        $siswa = $this->authenticatedStudent($request);
        $record = $this->izinQuery($siswa)->whereKey($izin)->first();

        if (! $record) {
            return $this->notFoundResponse();
        }

        if ($this->statusFromRaw($record->getRawOriginal('sta')) !== Status::MENUNGGU) {
            throw ValidationException::withMessages([
                'izin' => ['Izin hanya bisa dibatalkan saat status masih menunggu.'],
            ]);
        }

        DB::connection('mai1')->transaction(function () use ($record) {
            $record->update(['sta' => Status::DIBATALKAN->value]);
        });

        $record = $this->izinQuery($siswa)->whereKey($izin)->firstOrFail();

        return response()->json([
            'success' => true,
            'message' => 'Izin berhasil dibatalkan.',
            'data' => [
                'account_id' => $this->authenticatedAccountId($request),
                'nouid' => $siswa->indentitas?->nouid,
                'idsis' => (int) $siswa->id,
                'izin' => $this->transformIzin($record),
            ],
        ]);
    }

    protected function izinQuery(Siswa $siswa)
    {
        return Tizin::query()
            ->with(['jenis', 'documents'])
            ->where('idsis', $siswa->getAttribute('id'))
            ->latest('created_at')
            ->orderByDesc('id');
    }

    protected function transformIzin(Tizin $izin): array
    {
        $jenis = $izin->jenis;

        return [
            'id' => (int) $izin->id,
            'jenis_id' => $izin->jen !== null ? (int) $izin->jen : null,
            'jenis' => $jenis ? $this->transformJenis($jenis) : null,
            'title' => $jenis?->title,
            'tgl_mulai' => $this->formatDate($izin->tgl_mulai),
            'tgl_akhir' => $this->formatDate($izin->tgl_akhir),
            'ket' => $izin->ket,
            'dok' => $izin->dok,
            'dok_id' => is_numeric($izin->dok) ? (int) $izin->dok : null,
            'dokumen' => $izin->documents->map(fn(Timagable $document) => $this->transformDocument($document))->values()->all(),
            ...$this->statusPayload($izin),
            'can_cancel' => $this->statusFromRaw($izin->getRawOriginal('sta')) === Status::MENUNGGU,
            'created_at' => $this->formatDateTime($izin->created_at),
            'updated_at' => $this->formatDateTime($izin->updated_at),
        ];
    }

    protected function transformJenis(Tizinjenis $jenis): array
    {
        return [
            'id' => (int) $jenis->id,
            'name' => $jenis->name,
            'title' => $jenis->title,
            'active' => $jenis->getRawOriginal('sta') === null || (int) $jenis->getRawOriginal('sta') === 0,
        ];
    }

    protected function transformDocument(Timagable $document): array
    {
        return [
            'id' => (int) $document->id,
            'name' => $document->name,
            'url' => $document->url,
            'path' => $document->path,
            'mime_type' => $document->mime_type,
            'size' => $document->size !== null ? (int) $document->size : null,
            'size_label' => $document->image_size,
        ];
    }

    protected function statusPayload(Tizin $izin): array
    {
        $status = $this->statusFromRaw($izin->getRawOriginal('sta'));

        return [
            'status_code' => $status->value,
            'status' => $status->label(),
            'status_label' => ucfirst($status->label()),
            'sta' => $status->label(),
        ];
    }

    protected function summarize(Collection $izin): array
    {
        $summary = ['total' => $izin->count()];

        foreach (Status::cases() as $status) {
            $summary[$status->label()] = $izin
                ->filter(fn(Tizin $item) => $this->statusFromRaw($item->getRawOriginal('sta')) === $status)
                ->count();
        }

        return $summary;
    }

    protected function statusFromRaw(mixed $value): Status
    {
        if (is_int($value) || (is_string($value) && is_numeric($value))) {
            return Status::tryFrom((int) $value) ?? Status::tryDefault();
        }

        if (is_string($value)) {
            $normalized = strtolower($value);

            foreach (Status::cases() as $status) {
                if (strtolower($status->name) === $normalized || $status->label() === $normalized) {
                    return $status;
                }
            }
        }

        return Status::tryDefault();
    }

    protected function statuses(): array
    {
        return collect(Status::cases())
            ->map(fn(Status $status) => [
                'code' => $status->value,
                'status' => $status->label(),
                'label' => ucfirst($status->label()),
            ])
            ->values()
            ->all();
    }

    protected function uploadedDocument(Request $request): ?UploadedFile
    {
        return $request->file('dok')
            ?? $request->file('dokumen')
            ?? $request->file('document')
            ?? $request->file('file');
    }

    protected function authenticatedAccountId(Request $request): string
    {
        return (string) $request->attributes->get('auth_account_id');
    }

    protected function authenticatedStudent(Request $request): Siswa
    {
        $siswa = $request->attributes->get('auth_siswa');
        $siswa->loadMissing(['indentitas', 'kelsis']);

        return $siswa;
    }

    protected function formatDate($value): ?string
    {
        return $value ? Carbon::parse($value)->format('Y-m-d') : null;
    }

    protected function formatDateTime($value): ?string
    {
        return $value ? Carbon::parse($value)->toDateTimeString() : null;
    }

    protected function notFoundResponse(): JsonResponse
    {
        return response()->json([
            'success' => false,
            'message' => 'Izin tidak ditemukan untuk siswa ini.',
        ], 404);
    }
}
