<?php

namespace App\Http\Controllers;

use App\Models\TimeEntry;
use App\Models\StaffTaskType;
use App\Models\Job;
use App\Models\JobEmployeeTaskAssignment;
use Illuminate\Http\Request;
use Carbon\Carbon;

class TimesheetController extends Controller
{
    public function index()
    {
        $user        = auth()->user();
        $isTrades    = $user->role?->name === 'trades';
        $isProcessor = $user->role?->name === 'processor';
        $isEmployee  = $user->role?->name === 'factory_employee';

        if ($isProcessor) {
            $taskTypes = StaffTaskType::where('is_active', true)->where('task_category', 'processor')->orderBy('name')->get();
        } elseif ($isEmployee) {
            $taskTypes = StaffTaskType::where('is_active', true)->where('task_category', 'employee')->orderBy('name')->get();
        } else {
            $taskTypes = StaffTaskType::where('is_active', true)->orderBy('name')->get();
        }

        if ($isEmployee) {
            // Factory employees only see jobs that have been sent to manufacture
            $assignedJobIds = JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('task_status', '!=', 'completed')
                ->pluck('job_id')->unique();

            $jobs = Job::with(['contact'])
                ->whereIn('id', $assignedJobIds)
                ->where('stage', 'processing')
                ->where('sent_to_manufacture', true)   // Only show jobs sent to manufacture
                ->orderBy('job_number')
                ->get();

            $assignments = JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('task_status', '!=', 'completed')
                ->whereIn('job_id', $assignedJobIds)
                ->with('taskType', 'job.contact')
                ->orderBy('id', 'desc')
                ->get();

            // Filter assignments to only include jobs sent to manufacture
            $sentJobIds = Job::whereIn('id', $assignedJobIds)
                ->where('sent_to_manufacture', true)
                ->pluck('id')
                ->toArray();
            $assignments = $assignments->whereIn('job_id', $sentJobIds)->values();

            $jobTaskMap = [];
            foreach ($assignments as $a) {
                $jobTaskMap[$a->job_id][] = $a->task_type_id;
            }

            $allTaskTypesJson = $taskTypes->map(fn($t) => ['id' => $t->id, 'name' => $t->name])->values();

        } elseif ($isTrades) {
            $jobs = $user->assignedJobs()
                ->with('contact')
                ->where('status', '!=', 'completed')
                ->orderBy('job_number')
                ->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;

        } elseif ($isProcessor) {
            $jobs = Job::with(['contact', 'consultant', 'manager'])
                ->whereHas('checkMeasures', fn($q) => $q->where('status', 'completed'))
                ->where('stage', 'processing')
                ->orderBy('job_number', 'desc')
                ->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;

        } else {
            $jobs = Job::whereIn('status', ['active'])->orderBy('job_number')->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;
        }

        $running = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->with('taskType', 'job')
            ->first();

        $runningEntries = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->with('taskType', 'job')
            ->get();

        $pausedEntries = TimeEntry::where('user_id', $user->id)
            ->where('status', 'paused')
            ->with('taskType', 'job')
            ->orderByDesc('stopped_at')
            ->get();

        $entries = TimeEntry::where('user_id', $user->id)
            ->with('taskType', 'job')
            ->orderByDesc('started_at')
            ->paginate(20);

        $weekStart     = Carbon::now()->startOfWeek();
        $weeklyEntries = TimeEntry::where('user_id', $user->id)
            ->where('started_at', '>=', $weekStart)
            ->whereIn('status', ['paused', 'completed'])
            ->get();
        $weeklyHours    = $weeklyEntries->sum('duration_minutes') / 60;
        $weeklyEarnings = $weeklyHours * ($user->hourly_rate ?? 0);

        $statuscompleted = false;

        return view('timesheet.index', compact(
            'taskTypes', 'jobs', 'running', 'runningEntries', 'entries', 'weeklyHours', 'weeklyEarnings',
            'jobTaskMap', 'allTaskTypesJson', 'assignments', 'pausedEntries', 'statuscompleted'
        ));
    }

    public function timesheetemployeecompleted()
    {
        $user        = auth()->user();
        $isTrades    = $user->role?->name === 'trades';
        $isProcessor = $user->role?->name === 'processor';
        $isEmployee  = $user->role?->name === 'factory_employee';

        if ($isProcessor) {
            $taskTypes = StaffTaskType::where('is_active', true)->where('task_category', 'processor')->orderBy('name')->get();
        } elseif ($isEmployee) {
            $taskTypes = StaffTaskType::where('is_active', true)->where('task_category', 'employee')->orderBy('name')->get();
        } else {
            $taskTypes = StaffTaskType::where('is_active', true)->orderBy('name')->get();
        }

        if ($isEmployee) {
            $assignedJobIds = JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('task_status', 'completed')
                ->pluck('job_id')->unique();

            $jobs = Job::with(['contact'])
                ->whereIn('id', $assignedJobIds)
                ->where('stage', 'processing')
                ->where('sent_to_manufacture', true)
                ->orderBy('job_number')
                ->get();

            $assignments = JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('task_status', 'completed')
                ->whereIn('job_id', $assignedJobIds)
                ->with('taskType', 'job.contact')
                ->orderBy('id', 'desc')
                ->get();

            $jobTaskMap = [];
            foreach ($assignments as $a) {
                $jobTaskMap[$a->job_id][] = $a->task_type_id;
            }

            $allTaskTypesJson = $taskTypes->map(fn($t) => ['id' => $t->id, 'name' => $t->name])->values();

        } elseif ($isTrades) {
            $jobs = $user->assignedJobs()
                ->with('contact')
                ->where('status', '!=', 'completed')
                ->orderBy('job_number')
                ->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;

        } elseif ($isProcessor) {
            $jobs = Job::with(['contact', 'consultant', 'manager'])
                ->whereHas('checkMeasures', fn($q) => $q->where('status', 'completed'))
                ->where('stage', 'processing')
                ->orderBy('job_number', 'desc')
                ->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;

        } else {
            $jobs = Job::whereIn('status', ['active'])->orderBy('job_number')->get();
            $assignments      = collect();
            $jobTaskMap       = null;
            $allTaskTypesJson = null;
        }

        $running = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->with('taskType', 'job')
            ->first();

        $runningEntries = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->with('taskType', 'job')
            ->get();

        $pausedEntries = TimeEntry::where('user_id', $user->id)
            ->where('status', 'paused')
            ->with('taskType', 'job')
            ->orderByDesc('stopped_at')
            ->get();

        $entries = TimeEntry::where('user_id', $user->id)
            ->with('taskType', 'job')
            ->orderByDesc('started_at')
            ->paginate(20);

        $weekStart     = Carbon::now()->startOfWeek();
        $weeklyEntries = TimeEntry::where('user_id', $user->id)
            ->where('started_at', '>=', $weekStart)
            ->whereIn('status', ['paused', 'completed'])
            ->get();
        $weeklyHours    = $weeklyEntries->sum('duration_minutes') / 60;
        $weeklyEarnings = $weeklyHours * ($user->hourly_rate ?? 0);

        $statuscompleted = true;

        return view('timesheet.index', compact(
            'taskTypes', 'jobs', 'running', 'runningEntries', 'entries', 'weeklyHours', 'weeklyEarnings',
            'jobTaskMap', 'allTaskTypesJson', 'assignments', 'pausedEntries', 'statuscompleted'
        ));
    }

    public function start(Request $request)
    {
        $user        = auth()->user();
        $isEmployee  = $user->role?->name === 'factory_employee';
        $isProcessor = $user->role?->name === 'processor';
        $isMultiTimer = $isEmployee || $isProcessor; // both support multiple concurrent timers

        // For non-multi-timer users only: pause any currently running timer before starting a new one
        if (!$isMultiTimer) {
            $current = TimeEntry::where('user_id', $user->id)->where('status', 'running')->first();
            if ($current) {
                $mins = $current->started_at->diffInMinutes(now());
                $current->update([
                    'stopped_at'       => now(),
                    'duration_minutes' => $mins,
                    'status'           => 'paused',
                ]);
            }
        }
        // Factory employees and processors can run multiple timers simultaneously.

        $isTrades = $user->role?->name === 'trades';
        $rules = [
            'job_id' => 'required|exists:crm_jobs,id',
            'notes'  => 'nullable|string|max:255',
        ];
        if (!$isTrades) {
            $rules['task_type_id'] = 'required|exists:staff_task_types,id';
        }
        $data = $request->validate($rules);

        // For multi-timer users: prevent starting a duplicate running timer for the same job+task
        if ($isMultiTimer && isset($data['task_type_id']) && isset($data['job_id'])) {
            $alreadyRunning = TimeEntry::where('user_id', $user->id)
                ->where('status', 'running')
                ->where('job_id', $data['job_id'])
                ->where('task_type_id', $data['task_type_id'])
                ->exists();
            if ($alreadyRunning) {
                return back()->with('error', 'A timer for this task is already running.');
            }
        }

        TimeEntry::create([
            'user_id'      => $user->id,
            'task_type_id' => $data['task_type_id'] ?? null,
            'job_id'       => $data['job_id'] ?? null,
            'started_at'   => now(),
            'status'       => 'running',
            'notes'        => $data['notes'] ?? null,
        ]);

        // Mark task assignment as in_progress (factory employee only — processor has no assignments)
        if ($isEmployee && isset($data['task_type_id']) && isset($data['job_id'])) {
            JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('job_id', $data['job_id'])
                ->where('task_type_id', $data['task_type_id'])
                ->where('task_status', 'pending')
                ->update(['task_status' => 'in_progress']);
        }

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

    /**
     * Pause a running timer.
     * For factory employees and processors: requires job_id + task_type_id to identify which timer.
     * For other users: pauses whichever single timer is running.
     */
    public function stop(Request $request)
    {
        $user        = auth()->user();
        $isEmployee  = $user->role?->name === 'factory_employee';
        $isProcessor = $user->role?->name === 'processor';

        if ($isEmployee || $isProcessor) {
            // Target the specific task's running timer
            $entry = TimeEntry::where('user_id', $user->id)
                ->where('status', 'running')
                ->where('job_id', $request->input('job_id'))
                ->where('task_type_id', $request->input('task_type_id'))
                ->first();
        } else {
            // Single-timer users: pause whichever is running
            $entry = TimeEntry::where('user_id', $user->id)->where('status', 'running')->first();
        }

        if ($entry) {
            $mins = $entry->started_at->diffInMinutes(now());
            $entry->update([
                'stopped_at'       => now(),
                'duration_minutes' => $mins,
                'status'           => 'paused',
            ]);

            // Update assignment status (factory employee only)
            if ($isEmployee && $entry->task_type_id && $entry->job_id) {
                JobEmployeeTaskAssignment::where('user_id', $user->id)
                    ->where('job_id', $entry->job_id)
                    ->where('task_type_id', $entry->task_type_id)
                    ->where('task_status', 'in_progress')
                    ->update(['task_status' => 'paused']);
            }

            return back()->with('success', 'Timer paused. ' . $entry->elapsed . ' recorded. You can resume it anytime.');
        }
        return back()->with('error', 'No running timer found.');
    }

    /**
     * Resume a paused task — starts a new TimeEntry for same job+task.
     * For factory employees and processors: does NOT pause other running timers.
     * For other users: pauses any currently running timer first.
     */
    public function resume(Request $request)
    {
        $user        = auth()->user();
        $isEmployee  = $user->role?->name === 'factory_employee';
        $isProcessor = $user->role?->name === 'processor';
        $isMultiTimer = $isEmployee || $isProcessor;

        $data = $request->validate([
            'job_id'       => 'required|exists:crm_jobs,id',
            'task_type_id' => 'nullable|exists:staff_task_types,id',
        ]);

        // For single-timer users: pause any currently running timer first
        if (!$isMultiTimer) {
            $current = TimeEntry::where('user_id', $user->id)->where('status', 'running')->first();
            if ($current) {
                $mins = $current->started_at->diffInMinutes(now());
                $current->update([
                    'stopped_at'       => now(),
                    'duration_minutes' => $mins,
                    'status'           => 'paused',
                ]);
            }
        }
        // Multi-timer users: other timers keep running.

        // For multi-timer users: prevent duplicate running timer for same job+task
        if ($isMultiTimer && !empty($data['task_type_id'])) {
            $alreadyRunning = TimeEntry::where('user_id', $user->id)
                ->where('status', 'running')
                ->where('job_id', $data['job_id'])
                ->where('task_type_id', $data['task_type_id'])
                ->exists();
            if ($alreadyRunning) {
                return back()->with('error', 'A timer for this task is already running.');
            }
        }

        TimeEntry::create([
            'user_id'      => $user->id,
            'task_type_id' => $data['task_type_id'] ?? null,
            'job_id'       => $data['job_id'],
            'started_at'   => now(),
            'status'       => 'running',
            'notes'        => 'Resumed',
        ]);

        // Update assignment back to in_progress (factory employee only)
        if ($isEmployee && !empty($data['task_type_id'])) {
            JobEmployeeTaskAssignment::where('user_id', $user->id)
                ->where('job_id', $data['job_id'])
                ->where('task_type_id', $data['task_type_id'])
                ->whereIn('task_status', ['paused', 'pending'])
                ->update(['task_status' => 'in_progress']);
        }

        return back()->with('success', 'Timer resumed.');
    }

    /**
     * Complete a factory_employee task assignment.
     * Stops running timer, marks paused entries completed, marks assignment completed.
     */
    public function completeTask(Request $request)
    {
        $user = auth()->user();

        $data = $request->validate([
            'assignment_id' => 'required|exists:job_employee_task_assignments,id',
        ]);

        $assignment = JobEmployeeTaskAssignment::where('id', $data['assignment_id'])
            ->where('user_id', $user->id)
            ->firstOrFail();

        $running = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->where('job_id', $assignment->job_id)
            ->where('task_type_id', $assignment->task_type_id)
            ->first();

        if ($running) {
            $mins = $running->started_at->diffInMinutes(now());
            $running->update([
                'stopped_at'       => now(),
                'duration_minutes' => $mins,
                'status'           => 'completed',
            ]);
        }

        TimeEntry::where('user_id', $user->id)
            ->where('job_id', $assignment->job_id)
            ->where('task_type_id', $assignment->task_type_id)
            ->where('status', 'paused')
            ->update(['status' => 'completed']);

        $assignment->update(['task_status' => 'completed']);

        return back()->with('success', 'Task marked as completed. Hours are now included in the gross profit report.');
    }

    /**
     * Complete a processor task — stops running timer and marks all paused entries
     * as completed. Processor is a direct role so hours immediately affect gross profit.
     */
    public function completeProcessorTask(Request $request)
    {
        $user = auth()->user();

        if ($user->role?->name !== 'processor') {
            abort(403);
        }

        $data = $request->validate([
            'job_id'       => 'required|exists:crm_jobs,id',
            'task_type_id' => 'required|exists:staff_task_types,id',
        ]);

        // Stop any running timer for this job+task
        $running = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->where('job_id', $data['job_id'])
            ->where('task_type_id', $data['task_type_id'])
            ->first();

        if ($running) {
            $mins = $running->started_at->diffInMinutes(now());
            $running->update([
                'stopped_at'       => now(),
                'duration_minutes' => $mins,
                'status'           => 'completed',
            ]);
        }

        // Mark all paused entries for this task as completed
        TimeEntry::where('user_id', $user->id)
            ->where('job_id', $data['job_id'])
            ->where('task_type_id', $data['task_type_id'])
            ->where('status', 'paused')
            ->update(['status' => 'completed']);

        return back()->with('success', 'Task completed. Hours are now reflected in the gross profit report for this job.');
    }

    /**
     * Complete a trades job — stops any running timer and marks all paused/running
     * time entries for this job as completed so they can be invoiced.
     */
    public function completeTradeJob(Request $request)
    {
        $user = auth()->user();

        if ($user->role?->name !== 'trades') {
            abort(403);
        }

        $data = $request->validate([
            'job_id' => 'required|exists:crm_jobs,id',
        ]);

        $isAssigned = $user->assignedJobs()->where('crm_jobs.id', $data['job_id'])->exists();
        if (!$isAssigned) {
            return back()->with('error', 'You are not assigned to this job.');
        }

        $running = TimeEntry::where('user_id', $user->id)
            ->where('status', 'running')
            ->where('job_id', $data['job_id'])
            ->first();

        if ($running) {
            $mins = $running->started_at->diffInMinutes(now());
            $running->update([
                'stopped_at'       => now(),
                'duration_minutes' => $mins,
                'status'           => 'completed',
            ]);
        }

        $updatedCount = TimeEntry::where('user_id', $user->id)
            ->where('job_id', $data['job_id'])
            ->where('status', 'paused')
            ->update(['status' => 'completed']);

        $totalUpdated = ($running ? 1 : 0) + $updatedCount;

        if ($totalUpdated === 0) {
            return back()->with('error', 'No running or paused timers found for this job.');
        }

        return back()->with('success', 'Job completed. All time entries are now ready for invoice approval.');
    }

    public function destroy(TimeEntry $entry)
    {
        $user = auth()->user();
        if ($entry->user_id !== $user->id && $user->role?->name !== 'office_admin') {
            abort(403);
        }
        $entry->delete();
        return back()->with('success', 'Entry deleted.');
    }

    public function admin()
    {
        $entries = TimeEntry::with('user', 'taskType', 'job')
            ->orderByDesc('started_at')
            ->paginate(50);

        $users = \App\Models\User::with('role')
            ->whereHas('role', fn($q) => $q->whereIn('name', ['factory_employee', 'trades', 'processor']))
            ->orderBy('name')
            ->get();

        return view('timesheet.admin', compact('entries', 'users'));
    }
}
