<?php

namespace App\Http\Controllers;

use App\Models\Job;
use App\Models\ProcessingOrder;
use App\Models\ActivityLog;
use App\Models\User;
use App\Models\StaffTaskType;
use App\Models\JobEmployeeTaskAssignment;
use Illuminate\Http\Request;

class ProcessingController extends Controller
{
    public function index()
    {
        $user     = auth()->user();
        $isTrades = $user->role?->name === 'trades';

        $query = Job::with(['contact', 'processingOrders'])
            ->whereIn('stage', ['processing', 'delivery', 'installation']);

        if ($isTrades) {
            $query->whereHas('tradeUsers', fn($q) => $q->where('users.id', $user->id));
        }

        $jobs = $query->paginate(20);
        return view('processing.index', compact('jobs'));
    }

    public function show(Job $job)
    {
        // Trades users may only view jobs assigned to them
        $user = auth()->user();
        if ($user->role?->name === 'trades') {
            abort_unless(
                $user->assignedJobs()->where('crm_jobs.id', $job->id)->exists(),
                403
            );
        }

        $job->load([
            'contact', 'processingOrders', 'tasks',
            'employeeTaskAssignments.user', 'employeeTaskAssignments.taskType',
        ]);

        // Factory employees available to assign tasks to
        $factoryEmployees = User::whereHas('role', fn($q) => $q->where('name', 'factory_employee'))
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        // Employee task types (task_category = 'employee')
        $employeeTaskTypes = StaffTaskType::where('is_active', true)
            ->where('task_category', 'employee')
            ->orderBy('name')
            ->get();

        return view('processing.show', compact('job', 'factoryEmployees', 'employeeTaskTypes'));
    }

    public function storeOrder(Request $request, Job $job)
    {
        $data = $request->validate([
            'description' => 'required|string|max:255',
            'supplier'    => 'nullable|string|max:255',
            'order_date'  => 'nullable|date',
            'eta_date'    => 'nullable|date',
            'total_items' => 'nullable|integer|min:0',
            'notes'       => 'nullable|string',
        ]);

        $data['job_id'] = $job->id;
        $data['po_number'] = 'PO-' . str_pad((ProcessingOrder::max('id') ?? 0) + 1, 4, '0', STR_PAD_LEFT);
        $data['status'] = 'pending';
        $data['progress_pct'] = 0;
        $data['completed_items'] = 0;

        $order = ProcessingOrder::create($data);

        ActivityLog::create([
            'user_id' => auth()->id(), 'loggable_type' => 'ProcessingOrder', 'loggable_id' => $order->id,
            'action' => 'Order Created',
            'description' => "Processing order {$order->po_number} created for job {$job->job_number}",
        ]);

        return back()->with('success', "Processing order {$order->po_number} created.");
    }

    public function updateOrder(Request $request, ProcessingOrder $order)
    {
        $data = $request->validate([
            'status'          => 'required|in:pending,ordered,in_production,ready,delivered,cancelled',
            'supplier'        => 'nullable|string',
            'eta_date'        => 'nullable|date',
            'completed_items' => 'nullable|integer|min:0',
            'notes'           => 'nullable|string',
        ]);

        if (isset($data['completed_items']) && $order->total_items > 0) {
            $data['progress_pct'] = min(100, (int) round($data['completed_items'] / $order->total_items * 100));
        }

        $order->update($data);
        return back()->with('success', "Order {$order->po_number} updated.");
    }

    public function updateProgress(Request $request, ProcessingOrder $order)
    {
        $request->validate(['progress_pct' => 'required|integer|min:0|max:100']);
        $order->update(['progress_pct' => $request->progress_pct]);
        if ($request->progress_pct === 100) {
            $order->update(['status' => 'ready']);
        }
        return back()->with('success', 'Progress updated.');
    }

    /**
     * Assign one or more employee task types to a factory employee for this job.
     * Each selected task requires its own allocated_hours value.
     */
    public function assignEmployeeTask(Request $request, Job $job)
    {
        $request->validate([
            'user_id'         => 'required|exists:users,id',
            'task_type_ids'   => 'required|array|min:1',
            'task_type_ids.*' => 'required|exists:staff_task_types,id',
            'allocated_hours' => 'required|array',
        ]);

        $userId      = $request->input('user_id');
        $taskTypeIds = $request->input('task_type_ids', []);
        $hoursMap    = $request->input('allocated_hours', []);

        // Ensure every selected task has a valid hours value
        foreach ($taskTypeIds as $taskTypeId) {
            $hrs = $hoursMap[$taskTypeId] ?? null;
            if ($hrs === null || $hrs === '' || !is_numeric($hrs) || (float) $hrs < 0.5) {
                return back()
                    ->withInput()
                    ->withErrors(['allocated_hours' => 'Please provide valid allocated hours (minimum 0.5) for every selected task.']);
            }
        }

        $assigned = 0;
        $skipped  = 0;

        foreach ($taskTypeIds as $taskTypeId) {
            $exists = JobEmployeeTaskAssignment::where('job_id', $job->id)
                ->where('user_id', $userId)
                ->where('task_type_id', $taskTypeId)
                ->exists();

            if ($exists) {
                $skipped++;
                continue;
            }

            JobEmployeeTaskAssignment::create([
                'job_id'          => $job->id,
                'user_id'         => $userId,
                'task_type_id'    => $taskTypeId,
                'allocated_hours' => (float) $hoursMap[$taskTypeId],
                'task_status'     => 'pending',
            ]);

            $assigned++;
        }

        if ($assigned === 0) {
            return back()->with('error', 'All selected tasks are already assigned to this employee for this job.');
        }

        $msg = "{$assigned} " . ($assigned === 1 ? 'task' : 'tasks') . " assigned to employee successfully.";
        if ($skipped > 0) {
            $msg .= " {$skipped} " . ($skipped === 1 ? 'task was' : 'tasks were') . " already assigned and skipped.";
        }

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

    /**
     * Remove an employee task assignment.
     */
    public function removeEmployeeTask(JobEmployeeTaskAssignment $assignment)
    {
        $assignment->delete();
        return back()->with('success', 'Task assignment removed.');
    }
}
