<?php

namespace Modules\Operations\Controllers;

use App\Controllers\BaseController;
use App\Models\EmployeeModel;
use App\Models\InventoryAssetModel;
use App\Models\WorkOrderEquipmentModel;
use App\Models\WorkOrderModel;
use App\Models\WorkOrderStaffModel;
use App\Traits\ExportsReport;
use Modules\Operations\Services\WorkOrderService;

class WorkOrderController extends BaseController
{
    use ExportsReport;
    protected WorkOrderModel $orders;
    protected WorkOrderStaffModel $staff;
    protected WorkOrderEquipmentModel $equipment;
    protected WorkOrderService $service;
    protected EmployeeModel $employees;
    protected InventoryAssetModel $assets;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->orders     = new WorkOrderModel();
        $this->staff      = new WorkOrderStaffModel();
        $this->equipment  = new WorkOrderEquipmentModel();
        $this->service    = new WorkOrderService();
        $this->employees  = new EmployeeModel();
        $this->assets     = new InventoryAssetModel();
    }

    public function createForm()
    {
        return view('Modules\Operations\Views\work_orders\create', array_merge($this->baseViewData(), [
            'title' => 'Create Work Order',
            'order' => [],
        ]));
    }

    public function store()
    {
        if (! $this->validate([
            'title'          => 'required|min_length[2]|max_length[200]',
            'priority'       => 'permit_empty|in_list[low,normal,high,urgent]',
            'status'         => 'permit_empty|in_list[draft,open]',
            'scheduled_date' => 'permit_empty|valid_date',
            'due_date'       => 'permit_empty|valid_date',
            'location'       => 'permit_empty|max_length[200]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->create($this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/operations/work-orders/' . $result['id'])
            ->with('success', 'Work order created.');
    }

    public function show(int $id)
    {
        $order = $this->orders->find($id);
        if (! $order) {
            return redirect()->to('/operations/work-orders/status-tracking')
                ->with('error', 'Work order not found.');
        }

        return view('Modules\Operations\Views\work_orders\show', array_merge($this->baseViewData(), [
            'title'     => $order['number'],
            'order'     => $order,
            'staff'     => $this->staff->getForWorkOrder($id),
            'equipment' => $this->equipment->getForWorkOrder($id),
        ]));
    }

    public function editForm(int $id)
    {
        $order = $this->orders->find($id);
        if (! $order) {
            return redirect()->to('/operations/work-orders/status-tracking')
                ->with('error', 'Work order not found.');
        }

        if (! in_array($order['status'], [...WorkOrderModel::OPEN_STATUSES, 'rejected'], true)) {
            return redirect()->to('/operations/work-orders/' . $id)
                ->with('error', 'Only open or rejected work orders can be edited.');
        }

        return view('Modules\Operations\Views\work_orders\edit', array_merge($this->baseViewData(), [
            'title' => 'Edit Work Order',
            'order' => $order,
        ]));
    }

    public function update(int $id)
    {
        if (! $this->validate([
            'title'          => 'required|min_length[2]|max_length[200]',
            'priority'       => 'permit_empty|in_list[low,normal,high,urgent]',
            'scheduled_date' => 'permit_empty|valid_date',
            'due_date'       => 'permit_empty|valid_date',
            'location'       => 'permit_empty|max_length[200]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->update($id, $this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/operations/work-orders/' . $id)->with('success', 'Work order updated.');
    }

    public function assignStaff()
    {
        $workOrderId = $this->request->getGet('work_order_id')
            ? (int) $this->request->getGet('work_order_id')
            : null;

        $order = $workOrderId ? $this->orders->find($workOrderId) : null;
        if ($workOrderId && ! $order) {
            return redirect()->to('/operations/work-orders/assign-staff')
                ->with('error', 'Work order not found.');
        }

        return view('Modules\Operations\Views\work_orders\assign_staff', array_merge($this->baseViewData(), [
            'title'      => 'Assign Staff',
            'workOrders' => $this->orders->getAssignable(),
            'order'      => $order,
            'staff'      => $order ? $this->staff->getForWorkOrder((int) $order['id']) : [],
            'employees'  => $this->employees->scopeForList(null, 'active')->orderBy('full_name', 'ASC')->findAll(),
            'workOrderId'=> $workOrderId,
        ]));
    }

    public function storeStaff()
    {
        if (! $this->validate([
            'work_order_id' => 'required|is_natural_no_zero',
            'employee_id'   => 'required|is_natural_no_zero',
            'role'          => 'permit_empty|max_length[100]',
            'notes'         => 'permit_empty|max_length[500]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $workOrderId = (int) $this->request->getPost('work_order_id');
        $result = $this->service->assignStaff($workOrderId, $this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/operations/work-orders/assign-staff?work_order_id=' . $workOrderId)
            ->with('success', 'Staff assigned.');
    }

    public function removeStaff(int $id)
    {
        $row = $this->staff->find($id);
        $result = $this->service->removeStaff($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        $redirect = $row
            ? '/operations/work-orders/assign-staff?work_order_id=' . (int) $row['work_order_id']
            : '/operations/work-orders/assign-staff';

        return redirect()->to($redirect)->with('success', 'Staff removed.');
    }

    public function assignEquipment()
    {
        $workOrderId = $this->request->getGet('work_order_id')
            ? (int) $this->request->getGet('work_order_id')
            : null;

        $order = $workOrderId ? $this->orders->find($workOrderId) : null;
        if ($workOrderId && ! $order) {
            return redirect()->to('/operations/work-orders/assign-equipment')
                ->with('error', 'Work order not found.');
        }

        $assets = [];
        try {
            $assets = $this->assets->scopeForList(null, 'active')->orderBy('name', 'ASC')->findAll();
        } catch (\Throwable $e) {
            $assets = [];
        }

        return view('Modules\Operations\Views\work_orders\assign_equipment', array_merge($this->baseViewData(), [
            'title'      => 'Assign Equipment',
            'workOrders' => $this->orders->getAssignable(),
            'order'      => $order,
            'equipment'  => $order ? $this->equipment->getForWorkOrder((int) $order['id']) : [],
            'assets'     => $assets,
            'workOrderId'=> $workOrderId,
        ]));
    }

    public function storeEquipment()
    {
        if (! $this->validate([
            'work_order_id'      => 'required|is_natural_no_zero',
            'inventory_asset_id' => 'required|is_natural_no_zero',
            'notes'              => 'permit_empty|max_length[500]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $workOrderId = (int) $this->request->getPost('work_order_id');
        $result = $this->service->assignEquipment($workOrderId, $this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/operations/work-orders/assign-equipment?work_order_id=' . $workOrderId)
            ->with('success', 'Equipment assigned.');
    }

    public function returnEquipment(int $id)
    {
        $row = $this->equipment->find($id);
        $result = $this->service->returnEquipment($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        $redirect = $row
            ? '/operations/work-orders/assign-equipment?work_order_id=' . (int) $row['work_order_id']
            : '/operations/work-orders/assign-equipment';

        return redirect()->to($redirect)->with('success', 'Equipment marked as returned.');
    }

    public function removeEquipment(int $id)
    {
        $row = $this->equipment->find($id);
        $result = $this->service->removeEquipment($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        $redirect = $row
            ? '/operations/work-orders/assign-equipment?work_order_id=' . (int) $row['work_order_id']
            : '/operations/work-orders/assign-equipment';

        return redirect()->to($redirect)->with('success', 'Equipment assignment removed.');
    }

    public function statusTracking()
    {
        $search   = trim((string) $this->request->getGet('q'));
        $status   = $this->request->getGet('status') ?: null;
        $priority = $this->request->getGet('priority') ?: null;

        $builder = $this->orders->scopeForList($search ?: null, $status, $priority);
        if (! $status) {
            $builder->whereIn('work_orders.status', WorkOrderModel::OPEN_STATUSES);
        }

        $orders = $builder
            ->orderBy('work_orders.due_date', 'ASC')
            ->orderBy('work_orders.id', 'DESC')
            ->findAll();

        return view('Modules\Operations\Views\work_orders\status_tracking', array_merge($this->baseViewData(), [
            'title'   => 'Status Tracking',
            'orders'  => $orders,
            'filters' => compact('search', 'status', 'priority'),
        ]));
    }

    public function updateStatus(int $id)
    {
        if (! $this->validate([
            'status' => 'required|in_list[draft,open,in_progress,on_hold,pending_approval,rejected,completed,cancelled]',
        ])) {
            return redirect()->back()->with('error', 'Invalid status.');
        }

        $result = $this->service->updateStatus(
            $id,
            (string) $this->request->getPost('status'),
            $this->request->getPost('notes'),
            (int) $this->session->get('user_id')
        );

        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->back()->with('success', 'Work order status updated.');
    }

    public function submitForApproval(int $id)
    {
        $result = $this->service->submitForApproval($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->to('/operations/work-orders/' . $id)
            ->with('success', 'Work order submitted for approval.');
    }

    public function complete(int $id)
    {
        $result = $this->service->complete(
            $id,
            $this->request->getPost('completion_notes'),
            (int) $this->session->get('user_id')
        );

        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->to('/operations/work-orders/' . $id)->with('success', 'Work order completed.');
    }

    public function cancel(int $id)
    {
        $result = $this->service->cancel($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->to('/operations/work-orders/' . $id)->with('success', 'Work order cancelled.');
    }

    public function destroy(int $id)
    {
        $result = $this->service->delete($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->to('/operations/work-orders/status-tracking')
            ->with('success', 'Work order deleted.');
    }

    public function completionReports()
    {
        $from   = $this->request->getGet('from') ?: date('Y-m-01');
        $to     = $this->request->getGet('to') ?: date('Y-m-d');
        $search = trim((string) $this->request->getGet('q'));

        $orders = $this->orders->getCompletedForReport($from, $to, $search ?: null);

        $enriched = [];
        foreach ($orders as $order) {
            $order['staff_count'] = (new WorkOrderStaffModel())
                ->where('work_order_id', (int) $order['id'])
                ->countAllResults();
            $order['equipment_count'] = (new WorkOrderEquipmentModel())
                ->where('work_order_id', (int) $order['id'])
                ->where('returned_at', null)
                ->countAllResults();
            $enriched[] = $order;
        }

        if ($export = $this->exportTable(
            'completion_reports',
            'Completion Reports',
            ['Number', 'Title', 'Priority', 'Location', 'Completed', 'Staff', 'Equipment', 'Notes'],
            array_map(static fn ($o) => [
                $o['number'] ?? '',
                $o['title'] ?? '',
                $o['priority'] ?? '',
                $o['location'] ?? '',
                $o['completed_at'] ?? '',
                (int) ($o['staff_count'] ?? 0),
                (int) ($o['equipment_count'] ?? 0),
                $o['completion_notes'] ?? '',
            ], $enriched),
            $from . ' to ' . $to
        )) {
            return $export;
        }

        return view('Modules\Operations\Views\work_orders\completion_reports', array_merge($this->baseViewData(), [
            'title'   => 'Completion Reports',
            'orders'  => $enriched,
            'filters' => [
                'from'   => $from,
                'to'     => $to,
                'search' => $search,
            ],
            'totalCompleted' => count($enriched),
        ]));
    }
}
