<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Guru;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;

class GuruController extends Controller
{
    // ================================================================
    // HELPER — Username bersih tanpa gelar
    // Sama persis dengan yang ada di GuruImport agar konsisten
    // Contoh: "DR. H. BUDI SUDARSONO, S.PD., M.M" → "budisudarsono"
    // ================================================================
    private function generateUsername(string $namaAsli): string
    {
        // 1. Potong di koma pertama → buang gelar belakang
        $nama = explode(',', $namaAsli)[0];

        // 2. Daftar gelar depan
        $gelarDepan = [
            'Prof.',
            'Prof',
            'Dr.',
            'Dr',
            'dr.',
            'dr',
            'Drs.',
            'Drs.H.',
            'Drs',
            'Dra.',
            'Dra',
            'Ir.',
            'Ir',
            'H.',
            'H',
            'Hj.',
            'Hj',
            'KH.',
            'KH',
            'Lc.',
            'Lc',
            'Ust.',
            'Ust',
            'Ustadz',
            'Ustadzah',
        ];

        // Urutkan panjang → pendek agar tidak terpotong parsial
        usort($gelarDepan, fn($a, $b) => strlen($b) - strlen($a));

        $nama = trim($nama);
        foreach ($gelarDepan as $gelar) {
            if (stripos($nama, $gelar . ' ') === 0) {
                $nama = substr($nama, strlen($gelar) + 1);
                $nama = trim($nama);
            }
        }

        $username = strtolower(preg_replace('/[^a-zA-Z]/', '', $nama));
        return $username ?: 'guru' . rand(100, 999);
    }

    // ================================================================
    // HELPER — Email Gmail dari nama
    // ================================================================
    private function generateEmail(string $namaAsli): string
    {
        return $this->generateUsername($namaAsli) . '13@gmail.com';
    }

    // ================================================================
    // HELPER — Pastikan username unik
    // ================================================================
    private function uniqueUsername(string $base, ?int $excludeUserId = null): string
    {
        $username = $base;
        $counter  = 1;
        $query = User::where('username', $username);
        if ($excludeUserId) $query->where('id', '!=', $excludeUserId);

        while ($query->exists()) {
            $username = $base . $counter;
            $counter++;
            $query = User::where('username', $username);
            if ($excludeUserId) $query->where('id', '!=', $excludeUserId);
        }
        return $username;
    }

    // ================================================================
    // HELPER — Pastikan email unik
    // ================================================================
    private function uniqueEmail(string $base, ?int $excludeUserId = null): string
    {
        $email   = $base;
        $counter = 1;
        $query   = User::where('email', $email);
        if ($excludeUserId) $query->where('id', '!=', $excludeUserId);

        while ($query->exists()) {
            [$local, $domain] = explode('@', $base);
            $email = $local . $counter . '@' . $domain;
            $counter++;
            $query = User::where('email', $email);
            if ($excludeUserId) $query->where('id', '!=', $excludeUserId);
        }
        return $email;
    }

    // ================================================================
    // HELPER — Cek apakah kombinasi jenis_identitas + nomor_identitas
    // sudah terdaftar. Sengaja di-scope per jenis identitas, jadi NIP
    // "001" dan NIK "001" dianggap berbeda (tidak konflik), tapi NIP
    // "001" dengan NIP "001" lain pasti gagal.
    // ================================================================
    private function isIdentitasDuplikat(string $jenisIdentitas, string $nomorIdentitas, ?int $excludeGuruId = null): bool
    {
        $query = Guru::where('jenis_identitas', $jenisIdentitas)
            ->where('nomor_identitas', $nomorIdentitas);

        if ($excludeGuruId) {
            $query->where('id', '!=', $excludeGuruId);
        }

        return $query->exists();
    }

    // ================================================================
    // INDEX + PENCARIAN GURU
    // Pencarian berdasarkan: nama, jenis identitas, nomor identitas,
    // username, dan email guru.
    // ================================================================
    public function index(Request $request)
    {
        $search = trim($request->query('search', ''));

        $query = Guru::with('user')->latest();

        if ($search !== '') {
            $query->where(function ($q) use ($search) {
                $q->where('nama', 'like', "%{$search}%")
                    ->orWhere('jenis_identitas', 'like', "%{$search}%")
                    ->orWhere('nomor_identitas', 'like', "%{$search}%")
                    ->orWhereHas('user', function ($uq) use ($search) {
                        $uq->where('username', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

        $gurus = $query->get();

        return view('guru.index', compact('gurus', 'search'));
    }

    // ================================================================
    // CETAK QR (SATUAN / SEMUA)
    // ================================================================
    public function cetak(Request $request)
    {
        $id = $request->query('id');
        $gurus = $id ? Guru::where('id', $id)->get() : Guru::all();
        return view('guru.guru_cetak', compact('gurus'));
    }

    public function print(Request $request)
    {
        return $this->cetak($request);
    }

    // ================================================================
    // TAMBAH GURU
    // Password default : Gunungpari13
    // Username         : nama bersih tanpa gelar (huruf kecil)
    // Email            : dari form (wajib diisi admin)
    //
    // Validasi duplikat: kombinasi jenis_identitas + nomor_identitas
    // yang sama PASTI ditolak dengan notifikasi gagal yang jelas.
    // ================================================================
    public function store(Request $request)
    {
        $request->validate([
            'nama'            => 'required|string|max:255',
            'email'           => 'required|email|unique:users,email',
            'jenis_identitas' => 'required|in:NIP,NUPTK,NRG,NIK,NPK,PegID',
            'nomor_identitas' => 'required|string|max:50',
            'jenis_kelamin'   => 'required|in:L,P',
        ], [
            'nama.required'            => 'Nama guru wajib diisi.',
            'nama.max'                 => 'Nama guru maksimal 255 karakter.',
            'email.required'           => 'Email wajib diisi.',
            'email.email'              => 'Format email tidak valid.',
            'email.unique'             => 'Email ini sudah digunakan oleh akun lain.',
            'jenis_identitas.required' => 'Jenis identitas wajib dipilih.',
            'jenis_identitas.in'       => 'Jenis identitas tidak valid.',
            'nomor_identitas.required' => 'Nomor identitas wajib diisi.',
            'nomor_identitas.max'      => 'Nomor identitas maksimal 50 karakter.',
            'jenis_kelamin.required'   => 'Jenis kelamin wajib dipilih.',
            'jenis_kelamin.in'         => 'Jenis kelamin tidak valid.',
        ]);

        $nomorIdentitas = trim($request->nomor_identitas);

        // Cek duplikat kombinasi jenis + nomor identitas
        if ($this->isIdentitasDuplikat($request->jenis_identitas, $nomorIdentitas)) {
            return back()->withInput()->with(
                'error',
                "Gagal! Guru dengan jenis identitas \"{$request->jenis_identitas}\" dan nomor \"{$nomorIdentitas}\" sudah terdaftar."
            );
        }

        $username = $this->uniqueUsername($this->generateUsername($request->nama));

        try {
            DB::transaction(function () use ($request, $username, $nomorIdentitas) {
                $user = User::create([
                    'name'     => $request->nama,
                    'username' => $username,
                    'email'    => $request->email,
                    'password' => Hash::make('Gunungpari13'),
                    'role'     => 'guru',
                ]);

                Guru::create([
                    'user_id'         => $user->id,
                    'nama'            => $request->nama,
                    'jenis_identitas' => $request->jenis_identitas,
                    'nomor_identitas' => $nomorIdentitas,
                    'jenis_kelamin'   => $request->jenis_kelamin,
                    'qr_code'         => 'GURU-' . $nomorIdentitas,
                ]);
            });

            return redirect()->route('admin.guru.index')
                ->with('success', "Guru \"{$request->nama}\" berhasil ditambahkan! Username: {$username} | Password: Gunungpari13");
        } catch (\Exception $e) {
            return back()->withInput()->with('error', 'Gagal menambahkan guru: ' . $e->getMessage());
        }
    }

    // ================================================================
    // UPDATE GURU
    // Username TIDAK diubah agar guru tidak bingung saat login
    //
    // Validasi duplikat tetap berlaku, kecuali untuk data guru itu
    // sendiri (excludeGuruId).
    // ================================================================
    public function update(Request $request, $id)
    {
        // Seluruh proses (termasuk findOrFail) sengaja dibungkus try-catch
        // supaya SEMUA jenis kegagalan — data tidak ditemukan, duplikat,
        // maupun error tak terduga saat simpan — tetap menghasilkan
        // notifikasi "Gagal!" di Blade, bukan halaman error 404/500 polos.
        try {
            $guru = Guru::findOrFail($id);
            $user = User::findOrFail($guru->user_id);

            $request->validate([
                'nama'            => 'required|string|max:255',
                'email'           => 'required|email|unique:users,email,' . $user->id,
                'jenis_identitas' => 'required|in:NIP,NUPTK,NRG,NIK,NPK,PegID',
                'nomor_identitas' => 'required|string|max:50',
                'jenis_kelamin'   => 'required|in:L,P',
            ], [
                'nama.required'            => 'Nama guru wajib diisi.',
                'nama.max'                 => 'Nama guru maksimal 255 karakter.',
                'email.required'           => 'Email wajib diisi.',
                'email.email'              => 'Format email tidak valid.',
                'email.unique'             => 'Email ini sudah digunakan oleh akun lain.',
                'jenis_identitas.required' => 'Jenis identitas wajib dipilih.',
                'jenis_identitas.in'       => 'Jenis identitas tidak valid.',
                'nomor_identitas.required' => 'Nomor identitas wajib diisi.',
                'nomor_identitas.max'      => 'Nomor identitas maksimal 50 karakter.',
                'jenis_kelamin.required'   => 'Jenis kelamin wajib dipilih.',
                'jenis_kelamin.in'         => 'Jenis kelamin tidak valid.',
            ]);

            $nomorIdentitas = trim($request->nomor_identitas);

            // Cek duplikat kombinasi jenis + nomor identitas, kecuali data ini sendiri
            if ($this->isIdentitasDuplikat($request->jenis_identitas, $nomorIdentitas, $guru->id)) {
                return back()->withInput()->with(
                    'error',
                    "Gagal! Guru dengan jenis identitas \"{$request->jenis_identitas}\" dan nomor \"{$nomorIdentitas}\" sudah terdaftar."
                );
            }

            DB::transaction(function () use ($request, $guru, $user, $nomorIdentitas) {
                $user->update([
                    'name'  => $request->nama,
                    'email' => $request->email,
                    // username sengaja TIDAK diupdate
                ]);

                $guru->update([
                    'nama'            => $request->nama,
                    'jenis_identitas' => $request->jenis_identitas,
                    'nomor_identitas' => $nomorIdentitas,
                    'jenis_kelamin'   => $request->jenis_kelamin,
                    'qr_code'         => 'GURU-' . $nomorIdentitas,
                ]);
            });

            return redirect()->route('admin.guru.index')
                ->with('success', "Data guru \"{$request->nama}\" berhasil diperbarui.");
        } catch (\Illuminate\Validation\ValidationException $e) {
            // Biarkan Laravel menangani seperti biasa (redirect back dengan
            // $errors bag) — Blade sudah punya handler khusus untuk ini.
            throw $e;
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return redirect()->route('admin.guru.index')
                ->with('error', 'Gagal memperbarui: data guru tidak ditemukan (mungkin sudah dihapus).');
        } catch (\Exception $e) {
            return back()->withInput()->with('error', 'Gagal memperbarui data: ' . $e->getMessage());
        }
    }

    // ================================================================
    // HAPUS GURU + USER
    // ================================================================
    public function destroy($id)
    {
        try {
            $guru = Guru::findOrFail($id);
            $nama = $guru->nama;

            DB::transaction(function () use ($guru) {
                $userId = $guru->user_id;
                $guru->delete();
                User::where('id', $userId)->delete();
            });

            return redirect()->route('admin.guru.index')
                ->with('success', "Data guru \"{$nama}\" dan akun terkait berhasil dihapus.");
        } catch (\Exception $e) {
            return back()->with('error', 'Gagal menghapus data: ' . $e->getMessage());
        }
    }

    // ================================================================
    // IMPORT — dua mode:
    // 1. mapped_data (dari JS modal pemetaan kolom di blade)
    // 2. file Excel langsung (GuruImport class)
    //
    // Password default : Gunungpari13
    // Email default    : namaguru@gmail.com
    // Username         : nama bersih tanpa gelar
    //
    // Duplikat dicek berdasarkan kombinasi jenis_identitas +
    // nomor_identitas (bukan nomor_identitas saja), supaya notif
    // gagal akurat per baris.
    //
    // Notifikasi sukses & gagal SELALU dipisah jadi 2 session key:
    //   - 'success' / 'warning'      → ringkasan singkat (ditampilkan sebagai judul)
    //   - 'import_success_detail'    → daftar nama yang berhasil (join '||')
    //   - 'import_fail_detail'       → daftar nama + alasan yang gagal (join '||')
    // Dipakai sama persis di kedua mode supaya Blade cukup baca 1 format.
    // ================================================================
    public function import(Request $request)
    {
        if ($request->filled('mapped_data')) {
            // ── MODE MAPPED DATA ────────────────────────────────────────
            $rows = json_decode($request->mapped_data, true);

            if (empty($rows)) {
                return back()->with('error', 'Tidak ada data valid untuk diimport.');
            }

            $berhasil     = 0;
            $berhasilNama = [];
            $gagal        = [];

            foreach ($rows as $row) {
                $nama           = trim($row['nama'] ?? '');
                $jenisIdentitas = strtoupper(trim($row['jenis_identitas'] ?? 'NIP'));
                $nomorIdentitas = ltrim(trim($row['nomor_identitas'] ?? ''), "'");
                $emailExcel     = trim($row['email'] ?? '');

                if (empty($nama) || empty($nomorIdentitas)) continue;

                $jkRaw = strtoupper(trim($row['jenis_kelamin'] ?? ''));
                $jk = match (true) {
                    in_array($jkRaw, ['L', 'LAKI', 'LAKI-LAKI', 'LAKILAKI', 'MALE', 'M']) => 'L',
                    in_array($jkRaw, ['P', 'PEREMPUAN', 'WANITA', 'FEMALE', 'F'])          => 'P',
                    default => null,
                };

                if ($jk === null) {
                    $gagal[] = "{$nama}: jenis kelamin tidak dikenali ({$jkRaw}).";
                    continue;
                }

                // Cek duplikat kombinasi jenis + nomor identitas
                if ($this->isIdentitasDuplikat($jenisIdentitas, $nomorIdentitas)) {
                    $gagal[] = "{$nama}: identitas {$jenisIdentitas} {$nomorIdentitas} sudah terdaftar.";
                    continue;
                }

                // Email — gunakan dari Excel jika ada, kalau tidak pakai Gmail
                $email = !empty($emailExcel)
                    ? $emailExcel
                    : $this->generateEmail($nama);

                $email    = $this->uniqueEmail($email);
                $username = $this->uniqueUsername($this->generateUsername($nama));

                try {
                    DB::transaction(function () use ($nama, $jenisIdentitas, $nomorIdentitas, $jk, $email, $username) {
                        $user = User::create([
                            'name'     => $nama,
                            'email'    => $email,
                            'username' => $username,
                            'password' => Hash::make('Gunungpari13'),
                            'role'     => 'guru',
                        ]);

                        Guru::create([
                            'nama'            => $nama,
                            'jenis_identitas' => $jenisIdentitas ?: 'NIP',
                            'nomor_identitas' => $nomorIdentitas,
                            'jenis_kelamin'   => $jk,
                            'user_id'         => $user->id,
                            'qr_code'         => 'MTs-Guru-' . $nomorIdentitas,
                        ]);
                    });
                    $berhasil++;
                    $berhasilNama[] = "{$nama} ({$jenisIdentitas} {$nomorIdentitas})";
                } catch (\Exception $e) {
                    $gagal[] = "{$nama}: " . $e->getMessage();
                }
            }

            // Ringkasan singkat saja di 'warning'/'success' — detail per-baris
            // dipisah ke session key sendiri agar tidak numplek & gampang di-render.
            if (!empty($gagal)) {
                $msg      = "{$berhasil} guru berhasil diimport, " . count($gagal) . ' gagal.';
                $redirect = redirect()->route('admin.guru.index')
                    ->with('warning', $msg)
                    ->with('import_fail_detail', implode('||', $gagal));
            } else {
                $msg      = "{$berhasil} guru berhasil diimport.";
                $redirect = redirect()->route('admin.guru.index')->with('success', $msg);
            }

            if (!empty($berhasilNama)) {
                $redirect->with('import_success_detail', implode('||', $berhasilNama));
            }

            return $redirect;
        } else {
            // ── MODE FILE EXCEL LANGSUNG ────────────────────────────────
            $request->validate([
                'file' => 'required|mimes:xlsx,xls,csv',
            ], [
                'file.required' => 'Pilih file Excel terlebih dahulu.',
                'file.mimes'    => 'Format file harus .xlsx, .xls, atau .csv',
            ]);

            try {
                $import = new \App\Imports\GuruImport;
                Excel::import($import, $request->file('file'));

                $berhasil = count($import->berhasil);
                $gagal    = count($import->gagal);

                // Coba ambil daftar nama dari $import->berhasil (jika strukturnya string atau array/objek beratribut 'nama')
                $berhasilNama = collect($import->berhasil)->map(function ($item) {
                    if (is_string($item)) return $item;
                    if (is_array($item) && isset($item['nama'])) return $item['nama'];
                    if (is_object($item) && isset($item->nama)) return $item->nama;
                    return null;
                })->filter()->values();

                if ($gagal > 0) {
                    $msg    = "{$berhasil} guru berhasil diimport, {$gagal} gagal.";
                    $detail = collect($import->gagal)
                        ->map(fn($g) => "{$g['nama']}: {$g['alasan']}")
                        ->implode('||');

                    $redirect = redirect()->route('admin.guru.index')
                        ->with('warning', $msg)
                        ->with('import_fail_detail', $detail);
                } else {
                    $msg      = "{$berhasil} guru berhasil diimport.";
                    $redirect = redirect()->route('admin.guru.index')->with('success', $msg);
                }

                if ($berhasilNama->isNotEmpty()) {
                    $redirect->with('import_success_detail', $berhasilNama->implode('||'));
                }

                return $redirect;
            } catch (\Exception $e) {
                return back()->with('error', 'Gagal import: ' . $e->getMessage());
            }
        }
    }
}
