<?php

namespace App\Http\Controllers;

use App\Models\AttendanceSession;
use App\Models\DailyWorkLog;
use App\Models\LunchBreak;
use App\Models\Setting;
use Carbon\Carbon;
use Illuminate\Database\QueryException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;

class AttendanceController extends Controller
{
    public function index(): View
    {
        $user = Auth::user();
        $today = Carbon::now('Asia/Dhaka')->toDateString();

        $session = AttendanceSession::with(['lunchBreaks', 'workLogs'])
            ->where('user_id', $user->id)
            ->whereDate('attendance_date', $today)
            ->first();

        $lastOfficeStartTimeStr = Setting::where('key', 'last_office_start_time')->value('value') ?? '10:00:00';
        $now = Carbon::now('Asia/Dhaka');

        if (! $session && $now->format('H:i:s') > $lastOfficeStartTimeStr && $now->dayOfWeek !== Carbon::FRIDAY) {
            $session = AttendanceSession::create([
                'user_id' => $user->id,
                'attendance_date' => $today,
                'is_absent' => true,
                'status' => 'absent',
            ]);
        }

        $activityTimeline = [];

        if ($session) {
            if ($session->start_time) {
                $activityTimeline[] = [
                    'type' => 'start',
                    'label' => 'Office Started',
                    'time' => $session->start_time,
                    'description' => 'Start video captured',
                ];
            }

            foreach ($session->lunchBreaks as $lunch) {
                $activityTimeline[] = [
                    'type' => 'lunch_start',
                    'label' => 'Lunch Started',
                    'time' => $lunch->start_time,
                    'description' => 'Lunch break initiated',
                ];

                if ($lunch->end_time) {
                    $activityTimeline[] = [
                        'type' => 'lunch_end',
                        'label' => 'Lunch Ended',
                        'time' => $lunch->end_time,
                        'description' => 'Duration: '.((int) $lunch->duration_minutes).' mins',
                    ];
                }
            }

            foreach ($session->workLogs as $workLog) {
                $activityTimeline[] = [
                    'type' => 'work_log',
                    'label' => 'Work Log Submitted',
                    'time' => $workLog->created_at,
                    'description' => $workLog->title.' ('.str_replace('_', ' ', $workLog->completion_status).')',
                ];
            }

            if ($session->stop_time) {
                $activityTimeline[] = [
                    'type' => 'stop',
                    'label' => 'Office Stopped',
                    'time' => $session->stop_time,
                    'description' => 'Stop video captured',
                ];
            }

            usort($activityTimeline, function (array $a, array $b): int {
                return $a['time']->timestamp <=> $b['time']->timestamp;
            });
        }

        return view('attendance.index', [
            'session' => $session,
            'now' => $now,
            'activityTimeline' => $activityTimeline,
            'lastOfficeStartTimeStr' => $lastOfficeStartTimeStr,
        ]);
    }

    public function start(Request $request): RedirectResponse|JsonResponse
    {
        $user = Auth::user();
        $now = Carbon::now('Asia/Dhaka');
        $lastOfficeStartTimeStr = Setting::where('key', 'last_office_start_time')->value('value') ?? '10:00:00';

        if ($now->format('H:i:s') > $lastOfficeStartTimeStr && $now->dayOfWeek !== Carbon::FRIDAY) {
            return $this->respondAttendance(
                $request,
                false,
                'আজকের অফিস স্টার্ট করার সময় শেষ। আপনি আজকের দিনের জন্য absent।',
                422,
                [
                'attendance' => 'আজকের অফিস স্টার্ট করার সময় শেষ। আপনি আজকের দিনের জন্য absent।',
                ]
            );
        }

        $alreadyStarted = AttendanceSession::where('user_id', $user->id)
            ->whereDate('attendance_date', $now->toDateString())
            ->exists();

        if ($alreadyStarted) {
            return $this->respondAttendance(
                $request,
                false,
                'You have already started attendance today.',
                422,
                ['attendance' => 'You have already started attendance today.']
            );
        }

        $payload = $request->validate([
            'video_file' => ['required', 'file', 'mimes:webm,mp4,mov,m4v', 'max:51200'],
            'start_video_seconds' => ['required', 'integer', 'min:60'],
        ]);

        $startVideoPath = $request->file('video_file')->store(
            'attendance_videos/start',
            'public'
        );

        try {
            AttendanceSession::create([
                'user_id' => $user->id,
                'attendance_date' => $now->toDateString(),
                'start_time' => $now,
                'start_video_path' => $startVideoPath,
                'start_video_seconds' => $payload['start_video_seconds'],
                'status' => 'active',
            ]);
        } catch (QueryException $exception) {
            return $this->respondAttendance(
                $request,
                false,
                'You have already started attendance today.',
                422,
                ['attendance' => 'You have already started attendance today.']
            );
        }

        return $this->respondAttendance($request, true, 'Office start recorded successfully.');
    }

    public function stop(Request $request): RedirectResponse|JsonResponse
    {
        $user = Auth::user();
        $now = Carbon::now('Asia/Dhaka');

        $session = AttendanceSession::where('user_id', $user->id)
            ->whereDate('attendance_date', $now->toDateString())
            ->first();

        if (! $session) {
            return $this->respondAttendance(
                $request,
                false,
                'You must start office first.',
                422,
                ['attendance' => 'You must start office first.']
            );
        }

        if ($session->stop_time) {
            return $this->respondAttendance(
                $request,
                false,
                'Office already stopped for today.',
                422,
                ['attendance' => 'Office already stopped for today.']
            );
        }

        $payload = $request->validate([
            'video_file' => ['required', 'file', 'mimes:webm,mp4,mov,m4v', 'max:51200'],
            'stop_video_seconds' => ['required', 'integer', 'min:60'],
        ]);

        $stopVideoPath = $request->file('video_file')->store(
            'attendance_videos/stop',
            'public'
        );

        $lunchMinutes = (int) $session->lunchBreaks()->sum('duration_minutes');
        $totalMinutes = max(0, $session->start_time->diffInMinutes($now));
        $netMinutes = max(0, $totalMinutes - $lunchMinutes);

        $session->update([
            'stop_time' => $now,
            'stop_video_path' => $stopVideoPath,
            'stop_video_seconds' => $payload['stop_video_seconds'],
            'total_work_minutes' => $totalMinutes,
            'lunch_minutes' => $lunchMinutes,
            'net_work_minutes' => $netMinutes,
            'status' => 'completed',
        ]);

        return $this->respondAttendance($request, true, 'Office stop recorded successfully.');
    }

    public function lunchStart(): RedirectResponse
    {
        $session = $this->resolveActiveSession();

        if (! $session) {
            return back()->withErrors(['lunch' => 'Start office first to begin lunch.']);
        }

        if ($session->lunchBreaks()->whereNull('end_time')->exists()) {
            return back()->withErrors(['lunch' => 'Lunch is already running.']);
        }

        LunchBreak::create([
            'attendance_session_id' => $session->id,
            'start_time' => Carbon::now('Asia/Dhaka'),
        ]);

        return back()->with('success', 'Lunch started.');
    }

    public function lunchEnd(): RedirectResponse
    {
        $session = $this->resolveActiveSession();

        if (! $session) {
            return back()->withErrors(['lunch' => 'No active office session found.']);
        }

        $lunch = $session->lunchBreaks()->whereNull('end_time')->latest('id')->first();

        if (! $lunch) {
            return back()->withErrors(['lunch' => 'No active lunch found.']);
        }

        $end = Carbon::now('Asia/Dhaka');
        $duration = $lunch->start_time->diffInMinutes($end);

        $lunch->update([
            'end_time' => $end,
            'duration_minutes' => $duration,
            'is_over_limit' => $duration > 60,
        ]);

        return back()->with('success', 'Lunch ended.');
    }

    public function dailyLog(Request $request): RedirectResponse
    {
        $session = $this->resolveActiveSession();

        if (! $session) {
            return back()->withErrors(['work_log' => 'Start office before submitting daily work log.']);
        }

        $payload = $request->validate([
            'title' => ['required', 'string', 'max:150'],
            'description' => ['required', 'string'],
            'completion_status' => ['required', 'in:in_progress,completed,blocked'],
            'blocker' => ['nullable', 'string'],
            'remark' => ['nullable', 'string'],
        ]);

        DailyWorkLog::create([
            ...$payload,
            'attendance_session_id' => $session->id,
            'user_id' => $session->user_id,
        ]);

        return back()->with('success', 'Daily work log submitted.');
    }

    private function resolveActiveSession(): ?AttendanceSession
    {
        $user = Auth::user();
        $today = Carbon::now('Asia/Dhaka')->toDateString();

        return AttendanceSession::where('user_id', $user->id)
            ->whereDate('attendance_date', $today)
            ->whereNull('stop_time')
            ->first();
    }

    private function respondAttendance(
        Request $request,
        bool $success,
        string $message,
        int $statusCode = 200,
        array $errors = []
    ): RedirectResponse|JsonResponse {
        if ($request->expectsJson() || $request->ajax()) {
            return response()->json([
                'success' => $success,
                'message' => $message,
                'errors' => $errors,
            ], $statusCode);
        }

        if (! $success) {
            return back()->withErrors($errors ?: ['attendance' => $message]);
        }

        return back()->with('success', $message);
    }
}
