<?php

namespace App\Imports;

use App\Models\User;
use App\Models\Guru;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class GuruImport implements ToCollection, WithHeadingRow, WithBatchInserts, WithChunkReading
{
    protected $skipNip = [];
    protected $role;

    public function __construct($role)
    {
        $this->role = $role;
    }

    public function collection(Collection $rows)
    {
        $this->validateEmptyColumns($rows);
        $this->validateDuplicateNipExcelOnly($rows);
        $this->validateDataFormat($rows);
        $this->skipNip = $this->getExistingNips($rows);

        if (count($this->skipNip) === count($rows)) {
            throw new \Exception("Data NIP sudah terdaftar atau duplikat. Silakan cek file Excel Anda.");
        }

        DB::beginTransaction();

        try {
            foreach ($rows as $index => $row) {
                $nip = trim($row['nip']);
                $email = trim($row['email']);
                $rowNumber = $index + 2;

                if (in_array($nip, $this->skipNip)) {
                    continue;
                }

                if (User::where('email', $email)->exists()) {
                    continue;
                }

                $user = User::create([
                    'name'     => trim($row['name']),
                    'email'    => $email,
                    'password' => Hash::make($row['password']),
                    'role'     => $this->role,
                ]);

                Guru::create([
                    'guru_id'       => $user->id,
                    'nip'           => $nip,
                    'jenis_kelamin' => strtoupper(trim($row['jenis_kelamin'])),
                    'no_hp'         => '+' . trim($row['no_hp']),
                ]);
            }

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Import guru gagal', [
                'message' => $e->getMessage(),
                'trace'   => $e->getTraceAsString()
            ]);
            throw $e;
        }
    }

    private function validateEmptyColumns(Collection $rows)
    {
        $emptyColumns = [];
        $rowNumber = 2;

        foreach ($rows as $row) {
            $missingFields = [];

            if (empty(trim($row['name'] ?? ''))) $missingFields[] = 'name';
            if (empty(trim($row['email'] ?? ''))) $missingFields[] = 'email';
            if (empty(trim($row['nip'] ?? ''))) $missingFields[] = 'nip';
            if (empty(trim($row['jenis_kelamin'] ?? ''))) $missingFields[] = 'jenis_kelamin';
            if (empty(trim($row['no_hp'] ?? ''))) $missingFields[] = 'no_hp';
            if (empty(trim($row['password'] ?? ''))) $missingFields[] = 'password';

            if (!empty($missingFields)) {
                $emptyColumns[] = "Baris {$rowNumber}: kolom " . implode(', ', $missingFields) . " kosong";
            }

            $rowNumber++;
        }

        if (!empty($emptyColumns)) {
            throw new \Exception("Silakan isi data kolom yang kosong: " . implode("; ", $emptyColumns));
        }
    }

    private function validateDataFormat(Collection $rows)
    {
        $errors = [];
        $rowNumber = 2;

        foreach ($rows as $row) {
            $nip = trim($row['nip'] ?? '');
            $email = trim($row['email'] ?? '');
            $jk = strtoupper(trim($row['jenis_kelamin'] ?? ''));
            $noHp = trim($row['no_hp'] ?? '');

            // Validasi jenis kelamin
            if (!in_array($jk, ['L', 'P'])) {
                $errors[] = "Baris {$rowNumber} (NIP: {$nip}): Jenis kelamin harus L atau P";
            }

            // Validasi format email
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $errors[] = "Baris {$rowNumber} (NIP: {$nip}): Format email tidak valid";
            }

            // Validasi no HP
            if (!preg_match('/^62[0-9]{9,13}$/', $noHp)) {
                $errors[] = "Baris {$rowNumber} (NIP: {$nip}): No HP harus dimulai dengan 62 dan terdiri dari 11-15 digit angka";
            }

            $rowNumber++;
        }

        if (!empty($errors)) {
            throw new \Exception("Format data tidak valid: " . implode("; ", $errors));
        }
    }

    private function validateDuplicateNipExcelOnly(Collection $rows)
    {
        $nipTracker = [];
        $emailTracker = [];
        $duplicates = [];
        $rowNumber = 2;

        foreach ($rows as $row) {
            $nip = trim($row['nip'] ?? '');
            $email = trim($row['email'] ?? '');

            // Cek duplikat NIP dalam Excel
            if (isset($nipTracker[$nip])) {
                $duplicates[] = "NIP {$nip} duplikat antara baris {$nipTracker[$nip]} dan baris {$rowNumber}";
            } else {
                $nipTracker[$nip] = $rowNumber;
            }

            // Cek duplikat Email dalam Excel
            if (isset($emailTracker[$email])) {
                $duplicates[] = "Email {$email} duplikat antara baris {$emailTracker[$email]} dan baris {$rowNumber}";
            } else {
                $emailTracker[$email] = $rowNumber;
            }

            $rowNumber++;
        }

        if (!empty($duplicates)) {
            throw new \Exception("Data duplikat dalam Excel: " . implode("; ", $duplicates));
        }
    }

    private function getExistingNips(Collection $rows): array
    {
        $nips = $rows->pluck('nip')->map(fn($n) => trim($n ?? ''))->filter()->unique()->toArray();
        return Guru::whereIn('nip', $nips)->pluck('nip')->toArray();
    }

    public function batchSize(): int
    {
        return 100;
    }

    public function chunkSize(): int
    {
        return 100;
    }
}