<?php

namespace App\Http\Controllers;

use App\Models\Attendance;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Response;
use Illuminate\Validation\Rule;

class AbsensiController extends Controller
{
    /**
     * Tampilkan riwayat absensi pengguna saat ini.
     */
    public function indexUser(Request $request)
    {
        $this->finalizeExpiredAttendancesForUser(Auth::id());

        $baseQuery = Attendance::where('user_id', Auth::id());

        if ($request->filled('start_date')) {
            $baseQuery->whereDate('clock_in', '>=', $request->start_date);
        }

        if ($request->filled('end_date')) {
            $baseQuery->whereDate('clock_in', '<=', $request->end_date);
        }

        if ($request->filled('q')) {
            $q = $request->q;

            $baseQuery->where(function ($inner) use ($q) {
                $inner->where('status', 'like', "%{$q}%")
                      ->orWhere('note', 'like', "%{$q}%");
            });
        }

        $items = (clone $baseQuery)
            ->orderByDesc('clock_in')
            ->paginate(10)
            ->withQueryString();

        // Validasi diterima: clock_in & clock_out ada, durasi >= 12 jam
        $verifiedCount = (clone $baseQuery)
            ->whereNotNull('clock_in')
            ->whereNotNull('clock_out')
            ->get()
            ->filter(function ($item) {
                return $item->clock_in && $item->clock_out && $item->clock_in->diffInHours($item->clock_out) >= 12;
            })
            ->count();

        // Validasi ditolak: clock_in & clock_out ada, durasi < 12 jam
        $rejectedCount = (clone $baseQuery)
            ->whereNotNull('clock_in')
            ->whereNotNull('clock_out')
            ->get()
            ->filter(function ($item) {
                return $item->clock_in && $item->clock_out && $item->clock_in->diffInHours($item->clock_out) < 12;
            })
            ->count();

        $todayDate = now()->toDateString();
        $nowTz = now(config('app.timezone'));

        $attendanceEnabled = (bool) (Auth::user()->attendance_enabled ?? true);

        $todayAttendance = (clone $baseQuery)
            ->whereDate('clock_in', $todayDate)
            ->orderByDesc('clock_in')
            ->first();

        $openAttendance = (clone $baseQuery)
            ->whereNull('clock_out')
            ->where(function ($inner) {
                $inner->whereNull('status')->orWhere('status', 'hadir');
            })
            ->orderByDesc('clock_in')
            ->first();

        $canClockIn = $todayAttendance === null;
        $canMarkSpecial = $canClockIn;
        $canClockOut = $openAttendance !== null;
        $openClockInTime = $openAttendance?->clock_in?->timezone(config('app.timezone'));

        if (! $attendanceEnabled) {
            $canClockIn = false;
            $canMarkSpecial = false;
            $canClockOut = false;
        }

        return view('absensi.history', compact(
            'items',
            'verifiedCount',
            'rejectedCount',
            'todayAttendance',
            'openAttendance',
            'canClockIn',
            'canClockOut',
            'canMarkSpecial',
            'openClockInTime',
            'nowTz',
            'attendanceEnabled'
        ));
    }

    public function edit(Attendance $attendance)
    {
        abort_unless($attendance->user_id === Auth::id(), 403);

        $statuses = [
            'hadir' => 'Hadir',
            'izin' => 'Izin',
            'sakit' => 'Sakit',
            'alpha' => 'Alpha',
        ];

        return view('absensi.edit', [
            'attendance' => $attendance,
            'statuses' => $statuses,
        ]);
    }

    public function update(Request $request, Attendance $attendance)
    {
        abort_unless($attendance->user_id === Auth::id(), 403);

        $validated = $request->validate([
            'note' => ['nullable', 'string', 'max:255'],
            'action' => ['nullable', 'string', Rule::in(['update_note', 'mark_sick', 'mark_izin'])],
        ]);

        $action = $validated['action'] ?? 'update_note';

        if (in_array($action, ['mark_sick', 'mark_izin'], true)) {
            $status = $action === 'mark_sick' ? 'sakit' : 'izin';
            $attendance->update([
                'status' => $status,
                'note' => $validated['note'] ?? null,
                'clock_out' => null,
            ]);

            return redirect()
                ->route('user.absensi')
                ->with('status', 'Data absensi ditandai sebagai ' . strtoupper($status) . '.');
        }

        $attendance->update([
            'note' => $validated['note'] ?? null,
        ]);

        return redirect()
            ->route('user.absensi')
            ->with('status', 'Data absensi berhasil diperbarui.');
    }

    /**
     * Export data absensi user ke CSV
     */
    public function exportCsv(Request $request)
    {
        $query = Attendance::where('user_id', Auth::id());

        // Filter tanggal mulai
        if ($request->filled('start_date')) {
            $query->whereDate('clock_in', '>=', $request->start_date);
        }

        // Filter tanggal akhir
        if ($request->filled('end_date')) {
            $query->whereDate('clock_in', '<=', $request->end_date);
        }

        // Pencarian keyword status/catatan
        if ($request->filled('q')) {
            $q = $request->q;
            $query->where(function ($w) use ($q) {
                $w->where('status', 'like', "%{$q}%")
                  ->orWhere('note', 'like', "%{$q}%");
            });
        }

        $rows = $query->orderBy('clock_in')->get();

        $callback = function () use ($rows) {
            $out = fopen('php://output', 'w');

            // Header CSV
            fputcsv($out, ['Tanggal', 'Masuk', 'Keluar', 'Durasi (menit)', 'Status', 'Catatan']);

            foreach ($rows as $r) {
                $in = $r->clock_in ? $r->clock_in->timezone(config('app.timezone')) : null;
                $outAt = $r->clock_out ? $r->clock_out->timezone(config('app.timezone')) : null;
                $minutes = ($in && $outAt) ? $outAt->diffInMinutes($in) : 0;

                fputcsv($out, [
                    $in ? $in->format('Y-m-d') : '-',
                    $in ? $in->format('H:i') : '-',
                    $outAt ? $outAt->format('H:i') : '-',
                    $minutes,
                    $r->status ?? '-',
                    $r->note ?? '-',
                ]);
            }

            fclose($out);
        };

        $fname = 'absensi_' . now()->format('Ymd_His') . '.csv';

        return Response::streamDownload($callback, $fname, [
            'Content-Type' => 'text/csv',
        ]);
    }

    /**
     * Absen masuk (clock in)
     */
    public function clockIn(Request $request)
    {
        $userId = Auth::id();

        if (! (Auth::user()->attendance_enabled ?? true)) {
            return back()->withErrors([
                'absensi' => 'Absensi untuk akun Anda sedang dinonaktifkan oleh admin.',
            ]);
        }

        $this->finalizeExpiredAttendancesForUser($userId);

        $unfinishedAttendance = Attendance::where('user_id', $userId)
            ->whereNull('clock_out')
            ->where(function ($inner) {
                $inner->whereNull('status')->orWhere('status', 'hadir');
            })
            ->orderByDesc('clock_in')
            ->first();

        if ($unfinishedAttendance) {
            $openedAt = $unfinishedAttendance->clock_in?->timezone(config('app.timezone'));
            $dateLabel = $openedAt ? $openedAt->format('d M Y H:i') : 'sebelumnya';
            $nowTz = now(config('app.timezone'));

            if ($openedAt && $openedAt->isSameDay($nowTz)) {
                return back()->withErrors([
                    'absensi' => 'Anda masih memiliki absensi yang belum diselesaikan sejak ' . $dateLabel . '. Silakan selesaikan terlebih dahulu.',
                ]);
            }

            $autoRejectNote = 'Sistem: Absensi ditolak karena tidak melakukan absen keluar.';
            $note = trim($autoRejectNote . ' ' . ($unfinishedAttendance->note ?? ''));

            $unfinishedAttendance->update([
                'status' => 'alpha',
                'note' => $note,
            ]);

            $request->merge([
                'note' => trim($autoRejectNote . ' ' . ($request->note ?? '')),
            ]);
        }

        $todayDate = now()->toDateString();
        $hasTodayAttendance = Attendance::where('user_id', $userId)
            ->whereDate('clock_in', $todayDate)
            ->exists();

        if ($hasTodayAttendance) {
            return back()->withErrors([
                'absensi' => 'Anda sudah memiliki data absensi pada tanggal ini.',
            ]);
        }

        $validated = $request->validate([
            'selfie_photo' => 'required|image|mimes:jpeg,png,jpg|max:2048',
            'note' => 'nullable|string|max:255',
            'latitude' => 'nullable|numeric|between:-90,90',
            'longitude' => 'nullable|numeric|between:-180,180',
            'accuracy' => 'nullable|numeric|min:0',
            'location_name' => 'nullable|string|max:255',
        ]);

$path = $request->file('selfie_photo')->store('selfies', 'public');

Attendance::create([
    'user_id' => Auth::id(),
    'clock_in' => now(),
    'status' => 'hadir',
    'selfie_photo' => $path, // contoh: selfies/abc.jpg
    'clock_in_latitude' => $validated['latitude'] ?? null,
    'clock_in_longitude' => $validated['longitude'] ?? null,
    'clock_in_accuracy' => $validated['accuracy'] ?? null,
    'clock_in_location_name' => $validated['location_name'] ?? null,
    'note' => $validated['note'] ?? null,
]);


        return back()->with('status', 'Absen masuk berhasil.');
    }

    /**
     * Absen keluar (clock out)
     */
    public function clockOut(Request $request)
    {
        if (! (Auth::user()->attendance_enabled ?? true)) {
            return back()->withErrors(['absensi' => 'Absensi untuk akun Anda sedang dinonaktifkan oleh admin.']);
        }

        $this->finalizeExpiredAttendancesForUser(Auth::id());

        $attendance = Attendance::where('user_id', Auth::id())
            ->whereNull('clock_out')
            ->orderByDesc('clock_in')
            ->first();

        if (! $attendance) {
            return back()->withErrors(['absensi' => 'Belum ada absen masuk hari ini.']);
        }

        $clockIn = $attendance->clock_in?->timezone(config('app.timezone'));
        $now = now(config('app.timezone'));

        if ($clockIn && $now->greaterThan($clockIn->copy()->addHours(13))) {
            $attendance->update([
                'status' => 'alpha',
                'note' => trim('Sistem: Absen keluar ditolak karena melebihi batas 13 jam. ' . ($attendance->note ?? '')),
            ]);
            return back()->withErrors(['absensi' => 'Batas 13 jam telah terlampaui, absen keluar tidak dapat diproses.']);
        }

        // Jika kurang dari 12 jam, status jadi alpha (tidak diterima)
        if ($clockIn && $now->diffInHours($clockIn) < 12) {
            $attendance->update([
                'clock_out' => $now,
                'status' => 'alpha',
                'note' => trim(($attendance->note ? $attendance->note . ' ' : '') . 'Sistem: Absen keluar sebelum 12 jam, validasi tidak diterima.')
            ]);
            return back()->withErrors(['absensi' => 'Absen keluar tidak diterima karena belum 12 jam kerja. Status: Alpha.']);
        }

        $attendance->update([
            'clock_out' => $now,
            'status' => 'hadir',
        ]);

        return back()->with('status', 'Absen keluar berhasil.');
    }

    public function markSick(Request $request)
    {
        return $this->createSpecialAttendance($request, 'sakit');
    }

    public function markIzin(Request $request)
    {
        return $this->createSpecialAttendance($request, 'izin');
    }

    protected function createSpecialAttendance(Request $request, string $status)
    {
        if (! (Auth::user()->attendance_enabled ?? true)) {
            return back()->withErrors(['absensi' => 'Absensi untuk akun Anda sedang dinonaktifkan oleh admin.']);
        }

        $validated = $request->validate([
            'note' => ['nullable', 'string', 'max:255'],
        ]);

        $today = now()->toDateString();

        $alreadyExists = Attendance::where('user_id', Auth::id())
            ->whereDate('clock_in', $today)
            ->exists();

        if ($alreadyExists) {
            return back()->withErrors(['absensi' => 'Anda sudah memiliki data absensi pada tanggal ini.']);
        }

        Attendance::create([
            'user_id' => Auth::id(),
            'clock_in' => now(),
            'clock_out' => null,
            'status' => $status,
            'note' => $validated['note'] ?? null,
        ]);

        return back()->with('status', 'Absensi ' . ucfirst($status) . ' berhasil dicatat.');
    }

    protected function finalizeExpiredAttendancesForUser(int $userId): void
    {
        $openAttendances = Attendance::where('user_id', $userId)
            ->whereNull('clock_out')
            ->where(function ($inner) {
                $inner->whereNull('status')->orWhere('status', 'hadir');
            })
            ->get();

        if ($openAttendances->isEmpty()) {
            return;
        }

        $tz = config('app.timezone');
        $nowTz = now($tz);

        foreach ($openAttendances as $attendance) {
            $clockIn = $attendance->clock_in?->timezone($tz);

            if (! $clockIn) {
                continue;
            }

            $deadline = $clockIn->copy()->addHours(13);

            if ($nowTz->lessThan($deadline)) {
                continue;
            }

            $notePrefix = 'Sistem: Absensi otomatis ditolak karena tidak melakukan absen keluar dalam 13 jam (batas: ' . $deadline->format('d M Y H:i') . ').';
            $attendance->update([
                'clock_out' => $deadline->copy()->timezone($tz),
                'status' => 'alpha',
                'note' => trim($notePrefix . ' ' . ($attendance->note ?? '')),
            ]);
        }
    }
}
