<?php

namespace App\Http\Controllers\Publik;

use App\Http\Controllers\Controller;
use App\Models\JabatanFungsional;
use App\Models\KodeAksesKantor;
use App\Models\Pegawai;
use App\Models\PegawaiFile;
use App\Models\UnitKerja;
use App\Services\PegawaiEmailService;
use App\Support\PegawaiOptions;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

class PendataanController extends Controller
{
    /**
     * Show the public form
     */
    public function show(Request $request)
    {
        $kodeAkses = $this->activeOfficeCode($request);

        if (! $kodeAkses) {
            return view('public.office-code');
        }

        $formOptions = $this->formOptions($kodeAkses->unitKerja);

        return view('public.form', array_merge($formOptions, compact('kodeAkses')));
    }

    public function verifyOfficeCode(Request $request)
    {
        $validated = $request->validate([
            'kode' => ['required', 'string', 'max:32'],
        ]);

        $kode = Str::upper(trim($validated['kode']));
        $kodeAkses = KodeAksesKantor::with('unitKerja')
            ->where('kode', $kode)
            ->masihBerlaku()
            ->first();

        if (! $kodeAkses) {
            throw ValidationException::withMessages([
                'kode' => 'Kode kantor tidak valid, sudah kedaluwarsa, dinonaktifkan, atau kuotanya telah habis.',
            ]);
        }

        $request->session()->put('kode_akses_kantor_id', $kodeAkses->id);

        return redirect()->route('pegawai.form')
            ->with('success', 'Kode kantor berhasil diverifikasi.');
    }

    public function clearOfficeCode(Request $request)
    {
        $request->session()->forget('kode_akses_kantor_id');

        return redirect()->route('pegawai.form');
    }

    /**
     * Submit form dan simpan data pegawai
     */
    public function store(Request $request)
    {
        $kodeAkses = $this->activeOfficeCode($request);

        if (! $kodeAkses) {
            return redirect()->route('pegawai.form')
                ->with('error', 'Sesi kode kantor tidak berlaku. Silakan masukkan kode kembali.');
        }

        $validated = $request->validate([
            'nip' => ['required', 'string', 'size:18', 'regex:/^[0-9]{18}$/', Rule::unique('pegawai', 'nip')],
            'nama_lengkap' => 'required|string|max:255',
            'tempat_lahir' => 'required|string|max:255',
            'tanggal_lahir' => 'required|date|before:today',
            'jenis_kelamin' => 'required|in:Laki-laki,Perempuan',
            'alamat' => 'required|string|max:1000',
            'no_hp' => ['required', 'string', 'regex:/^[0-9]{10,13}$/', Rule::unique('pegawai', 'no_hp')],
            'email' => ['required', 'email', 'max:255', Rule::unique('pegawai', 'email')],
            'unit_kerja' => ['required', 'string', Rule::in([$kodeAkses->unitKerja->nama_unit])],
            'pendidikan_terakhir' => ['required', Rule::in(PegawaiOptions::pendidikan())],
            'golongan' => ['required', Rule::in($this->golonganOptions())],
            'jabatan_fungsional_id' => 'required|exists:jabatan_fungsional,id',
            'tanggal_mulai_jabatan' => 'required|date',
            'file' => 'required|file|mimes:pdf|max:1024', // 1MB max, PDF only
        ], [
            'nip.size' => 'NIP harus terdiri dari 18 digit.',
            'nip.regex' => 'NIP harus berupa 18 digit angka.',
            'nip.unique' => 'NIP sudah terdaftar di sistem.',
            'no_hp.regex' => 'Nomor telepon harus berupa 10-13 digit angka.',
            'no_hp.unique' => 'Nomor telepon sudah terdaftar di sistem.',
            'email.unique' => 'Email sudah terdaftar di sistem.',
            'file.required' => 'SK Pengangkatan Terbaru wajib diunggah.',
            'file.mimes' => 'File harus berformat PDF.',
        ]);

        $this->ensureJabatanMatchesUnitKerja($validated);

        $validated['status_validasi'] = 'pending';

        $pegawai = DB::transaction(function () use ($kodeAkses, $validated) {
            $lockedCode = KodeAksesKantor::whereKey($kodeAkses->id)
                ->lockForUpdate()
                ->first();

            if (! $lockedCode || ! $lockedCode->masihBisaDigunakan()) {
                throw ValidationException::withMessages([
                    'kode' => 'Kuota kode kantor telah habis atau kode sudah tidak berlaku.',
                ]);
            }

            $pegawai = Pegawai::create($validated);
            $lockedCode->increment('jumlah_digunakan');

            return $pegawai;
        });

        $this->storeUploadedFile($request, $pegawai);

        app(PegawaiEmailService::class)->send($pegawai);
        $request->session()->forget('kode_akses_kantor_id');

        return redirect()->route('pegawai.success', $pegawai->id)
            ->with('success', 'Data pegawai berhasil disimpan dan menunggu validasi admin.');
    }

    /**
     * Show correction form for rejected submission
     */
    public function editRejected(Pegawai $pegawai)
    {
        $pegawai->load('files');

        if ($pegawai->status_validasi !== 'ditolak') {
            return redirect()->route('pegawai.success', $pegawai)
                ->with('success', 'Data pendataan ini tidak sedang ditolak.');
        }

        $lockedUnitKerja = \App\Models\UnitKerja::where('nama_unit', $pegawai->unit_kerja)->first();

        return view('public.form', array_merge($this->formOptions($lockedUnitKerja), [
            'pegawai' => $pegawai,
            'isCorrection' => true,
            'formAction' => URL::temporarySignedRoute(
                'pegawai.correction.update',
                now()->addDays(7),
                ['pegawai' => $pegawai->id]
            ),
        ]));
    }

    /**
     * Update rejected submission and return it to pending status
     */
    public function updateRejected(Request $request, Pegawai $pegawai)
    {
        abort_unless($pegawai->status_validasi === 'ditolak', 403, 'Data ini tidak sedang ditolak.');

        $validated = $request->validate([
            'nip' => ['required', 'string', 'size:18', 'regex:/^[0-9]{18}$/', Rule::unique('pegawai', 'nip')->ignore($pegawai->id)],
            'nama_lengkap' => 'required|string|max:255',
            'tempat_lahir' => 'required|string|max:255',
            'tanggal_lahir' => 'required|date|before:today',
            'jenis_kelamin' => 'required|in:Laki-laki,Perempuan',
            'alamat' => 'required|string|max:1000',
            'no_hp' => ['required', 'string', 'regex:/^[0-9]{10,13}$/', Rule::unique('pegawai', 'no_hp')->ignore($pegawai->id)],
            'email' => ['required', 'email', 'max:255', Rule::unique('pegawai', 'email')->ignore($pegawai->id)],
            'unit_kerja' => 'required|string|max:255|exists:unit_kerja,nama_unit',
            'pendidikan_terakhir' => ['required', Rule::in(PegawaiOptions::pendidikan())],
            'golongan' => ['required', Rule::in($this->golonganOptions())],
            'jabatan_fungsional_id' => 'required|exists:jabatan_fungsional,id',
            'tanggal_mulai_jabatan' => 'required|date',
            'file' => 'nullable|file|mimes:pdf|max:1024',
        ], [
            'nip.size' => 'NIP harus terdiri dari 18 digit.',
            'nip.regex' => 'NIP harus berupa 18 digit angka.',
            'nip.unique' => 'NIP sudah terdaftar di sistem.',
            'no_hp.regex' => 'Nomor telepon harus berupa 10-13 digit angka.',
            'no_hp.unique' => 'Nomor telepon sudah terdaftar di sistem.',
            'email.unique' => 'Email sudah terdaftar di sistem.',
            'file.mimes' => 'File harus berformat PDF.',
        ]);

        $this->ensureJabatanMatchesUnitKerja($validated);

        $validated['status_validasi'] = 'pending';
        $validated['catatan_penolakan'] = null;

        $pegawai->update($validated);

        if ($request->hasFile('file')) {
            $this->deleteExistingFiles($pegawai);
            $this->storeUploadedFile($request, $pegawai);
        }

        app(PegawaiEmailService::class)->send($pegawai, 'status_updated');

        return redirect()->route('pegawai.success', $pegawai->id)
            ->with('success', 'Data berhasil diperbaiki dan kembali menunggu validasi admin.');
    }

    /**
     * Show success page
     */
    public function success(Pegawai $pegawai)
    {
        return view('public.success', compact('pegawai'));
    }

    public function showFile(PegawaiFile $file)
    {
        abort_unless(Storage::disk('public')->exists($file->path), 404);

        return response()->file(Storage::disk('public')->path($file->path));
    }

    private function formOptions(?UnitKerja $lockedUnitKerja = null): array
    {
        $jabatanList = JabatanFungsional::with('jenjangJabatan')
            ->when($lockedUnitKerja, fn ($query) => $query->where('unit_kerja_id', $lockedUnitKerja->id))
            ->orderBy('nama_jabatan')
            ->orderBy('jenjang_jabatan_id')
            ->get();

        return [
            'jabatanList' => $jabatanList,
            'jabatanOptions' => $jabatanList->map(fn ($jabatan) => [
                'id' => $jabatan->id,
                'nama_jabatan' => $jabatan->nama_jabatan,
                'jenjang_label' => $jabatan->jenjang_label,
                'unit_kerja_id' => $jabatan->unit_kerja_id,
            ])->values(),
            'unitKerjaList' => $lockedUnitKerja
                ? collect([$lockedUnitKerja])
                : UnitKerja::orderBy('nama_unit')->get(),
            'lockedUnitKerja' => $lockedUnitKerja,
            'golonganList' => $this->golonganOptions(),
            'pendidikanList' => PegawaiOptions::pendidikan(),
            'pegawai' => null,
            'isCorrection' => false,
            'formAction' => route('pegawai.store'),
        ];
    }

    private function storeUploadedFile(Request $request, Pegawai $pegawai): void
    {
        if (!$request->hasFile('file')) {
            return;
        }

        $file = $request->file('file');
        $fileName = Str::uuid() . '_' . $file->getClientOriginalName();
        $path = $file->storeAs('pegawai-files', $fileName, 'public');

        PegawaiFile::create([
            'pegawai_id' => $pegawai->id,
            'nama_file' => $file->getClientOriginalName(),
            'tipe_file' => $file->getClientOriginalExtension(),
            'path' => $path,
        ]);
    }

    private function deleteExistingFiles(Pegawai $pegawai): void
    {
        foreach ($pegawai->files()->get() as $file) {
            Storage::disk('public')->delete($file->path);
            $file->delete();
        }
    }

    private function golonganOptions(): array
    {
        return [
            ...PegawaiOptions::golongan(),
        ];
    }

    private function ensureJabatanMatchesUnitKerja(array $validated): void
    {
        $unitKerja = UnitKerja::where('nama_unit', $validated['unit_kerja'])->first();
        $isValid = $unitKerja && JabatanFungsional::whereKey($validated['jabatan_fungsional_id'])
            ->where('unit_kerja_id', $unitKerja->id)
            ->exists();

        if (!$isValid) {
            throw ValidationException::withMessages([
                'jabatan_fungsional_id' => 'Jabatan fungsional tidak tersedia pada unit kerja yang dipilih.',
            ]);
        }
    }

    private function activeOfficeCode(Request $request): ?KodeAksesKantor
    {
        $codeId = $request->session()->get('kode_akses_kantor_id');

        if (! $codeId) {
            return null;
        }

        $kodeAkses = KodeAksesKantor::with('unitKerja')
            ->whereKey($codeId)
            ->masihBerlaku()
            ->first();

        if (! $kodeAkses) {
            $request->session()->forget('kode_akses_kantor_id');
        }

        return $kodeAkses;
    }

}
