<?php

namespace App\Services;

use App\Models\Attendance;
use App\Models\Participant;
use App\Models\Program;
use App\Models\ProgramParticipant;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use League\Csv\Reader;

class ParticipantImportService
{
    // Column 1 must match one of these (normalized), Column 2 must match one of these
    private const VALID_COL1 = ['name', 'nama'];
    private const VALID_COL2 = ['nokp', 'ic', 'nric'];

    private function normalizeKey(string $key): string
    {
        return strtolower(preg_replace('/[^a-z0-9]/i', '', $key));
    }

    public function import(Program $program, UploadedFile $file, ?string $defaultSession, bool $markAttendance = false): array
    {
        $result = ['success' => 0, 'duplicates' => 0, 'failed' => 0, 'errors' => [], 'all_empty_ic' => false, 'invalid_headers' => false];

        $csv = Reader::createFromPath($file->getRealPath(), 'r');
        $csv->setHeaderOffset(0);

        $csv->setOutputBOM('');
        try {
            $csv->addStreamFilter('convert.iconv.UTF-8/UTF-8');
        } catch (\Throwable) {}

        // Validate headers — first two columns are mandatory and must be in order
        $rawHeaders    = $csv->getHeader();
        $normHeaders   = array_map(fn($h) => $this->normalizeKey($h), $rawHeaders);

        $col1 = $normHeaders[0] ?? '';
        $col2 = $normHeaders[1] ?? '';

        if (! in_array($col1, self::VALID_COL1) || ! in_array($col2, self::VALID_COL2)) {
            $result['invalid_headers'] = true;
            $result['found_headers']   = implode(', ', array_slice($rawHeaders, 0, 5));
            return $result;
        }

        // Collect all rows first to detect all_empty_ic
        $rows = [];
        foreach ($csv->getRecords() as $rowNum => $row) {
            $row = array_map('trim', $row);
            $row = array_combine(
                array_map(fn($k) => $this->normalizeKey($k), array_keys($row)),
                array_values($row)
            );
            $rows[$rowNum] = $row;
        }

        if (empty($rows)) {
            return $result;
        }

        // If every row has an empty no_kp, offer delete instead
        $noKpValues = array_map(
            fn($row) => preg_replace('/[^0-9]/', '', $row['nokp'] ?? $row['ic'] ?? ''),
            $rows
        );
        if (count(array_filter($noKpValues)) === 0) {
            $result['all_empty_ic'] = true;
            return $result;
        }

        $session = $defaultSession ?? $program->default_staff_session;

        foreach ($rows as $rowNum => $row) {
            $data = [
                'name'   => $row['name']   ?? $row['nama']    ?? '',
                'no_kp'  => preg_replace('/[^0-9]/', '', $row['nokp'] ?? $row['ic'] ?? ''),
                'email'  => $row['email']  ?? $row['emel']    ?? null,
                'phone'  => $row['phone']  ?? $row['telefon'] ?? null,
                'agency' => $row['agency'] ?? $row['agensi']  ?? $row['jabatan'] ?? null,
            ];

            $validator = Validator::make($data, [
                'name'  => ['required', 'string', 'max:255'],
                'no_kp' => ['required', 'digits:12'],
                'email' => ['nullable', 'email', 'max:255'],
                'phone' => ['nullable', 'string', 'max:20'],
            ]);

            if ($validator->fails()) {
                $result['failed']++;
                $result['errors'][] = 'Baris ' . ($rowNum + 2) . ': ' . implode(', ', $validator->errors()->all());
                continue;
            }

            try {
                DB::transaction(function () use ($program, $data, $session, $markAttendance, &$result) {
                    $participant = Participant::firstOrCreate(
                        ['no_kp' => $data['no_kp']],
                        [
                            'name'             => $data['name'],
                            'email'            => $data['email'] ?: null,
                            'phone'            => $data['phone'] ?: null,
                            'agency'           => $data['agency'] ?: null,
                            'participant_type' => 'staff',
                        ]
                    );

                    // Kemaskini emel, telefon dan agensi jika peserta sedia ada dan CSV ada data
                    if (! $participant->wasRecentlyCreated) {
                        $updates = [];
                        if (! empty($data['email']))  $updates['email']  = $data['email'];
                        if (! empty($data['phone']))  $updates['phone']  = $data['phone'];
                        if (! empty($data['agency'])) $updates['agency'] = $data['agency'];
                        if ($updates) $participant->update($updates);
                    }

                    $pp = $program->programParticipants()
                                  ->where('participant_id', $participant->id)
                                  ->first();

                    if ($pp) {
                        // Participant already registered
                        if ($markAttendance) {
                            $this->recordAttendance($program, $participant, $pp, $session);
                            $result['duplicates']++;
                        } else {
                            $result['duplicates']++;
                        }
                        return;
                    }

                    $newStatus = $markAttendance ? 'checked_in' : 'registered';

                    $pp = $program->programParticipants()->create([
                        'participant_id'         => $participant->id,
                        'registration_source'    => 'import',
                        'is_pre_registered'      => true,
                        'pre_registered_session' => $session,
                        'status'                 => $newStatus,
                        'registered_at'          => now(),
                    ]);

                    if ($markAttendance) {
                        $this->recordAttendance($program, $participant, $pp, $session);
                    }

                    $result['success']++;
                });
            } catch (\Throwable $e) {
                $result['failed']++;
                $result['errors'][] = 'Baris ' . ($rowNum + 2) . ': Ralat sistem — ' . $e->getMessage();
            }
        }

        return $result;
    }

    private function recordAttendance(Program $program, Participant $participant, ProgramParticipant $pp, ?string $session): void
    {
        $alreadyAttended = Attendance::where('program_id', $program->id)
                                     ->where('participant_id', $participant->id)
                                     ->exists();
        if ($alreadyAttended) {
            return;
        }

        $pp->update(['status' => 'checked_in']);

        Attendance::create([
            'program_id'             => $program->id,
            'participant_id'         => $participant->id,
            'program_participant_id' => $pp->id,
            'attendance_source'      => 'import',
            'attendance_session'     => $session ?? 'full_day',
            'checked_in_at'          => now(),
        ]);
    }
}
