<?php
namespace App\Controllers;

class JobCards extends BaseController
{
    public function index()
    {
        $role = session()->get('user_role');
        $uid  = session()->get('user_id');

        $q = $this->db->table('job_cards jc')
            ->select('jc.*, wo.wo_number, wo.title as wo_title, f.name as facility_name,
                      u.name as assigned_to_name, cu.name as created_by_name')
            ->join('work_orders wo', 'wo.id=jc.wo_id',      'left')
            ->join('facilities f',  'f.id=wo.facility_id',  'left')
            ->join('users u',       'u.id=jc.assigned_to',  'left')
            ->join('users cu',      'cu.id=jc.created_by',  'left');

        if ($role === 'technician') {
            $q->where('jc.assigned_to', $uid);
        }
        $this->scopeFacilities($q, 'wo.facility_id');

        $pg          = $this->paginate(25);
        $perPage     = $pg['perPage'];
        $currentPage = $pg['page'];
        $offset      = $pg['offset'];
        $total       = (clone $q)->countAllResults(false);
        $jobCards    = $q->orderBy('jc.created_at', 'DESC')
            ->limit($perPage, $offset)
            ->get()
            ->getResultArray();

        $kpi = [
            'draft'       => $this->db->table('job_cards')->where('status','draft')->countAllResults(),
            'in_progress' => $this->db->table('job_cards')->where('status','in_progress')->countAllResults(),
            'completed'   => $this->db->table('job_cards')->where('status','completed')->countAllResults(),
            'approved'    => $this->db->table('job_cards')->where('status','approved')->countAllResults(),
        ];

        return view('job_cards/index', $this->viewData([
            'title'       => 'Job Cards',
            'jobCards'    => $jobCards,
            'kpi'         => $kpi,
            'totalCount'  => $total,
            'perPage'     => $perPage,
            'currentPage' => $currentPage,
        ]));
    }

    public function create()
    {
        $woId = $this->request->getGet('wo_id');
        $wo   = null;

        if ($woId) {
            $wo = $this->db->table('work_orders w')
                ->select('w.*, f.name as facility_name')
                ->join('facilities f','f.id=w.facility_id','left')
                ->where('w.id', (int)$woId)->get()->getRowArray();
        }

        $workOrders = $this->db->table('work_orders w')
            ->select('w.id, w.wo_number, w.title, f.name as facility_name')
            ->join('facilities f','f.id=w.facility_id','left')
            ->whereIn('w.status',['assigned','in_progress'])
            ->orderBy('w.created_at','DESC')->get()->getResultArray();

        // FIX CQ-06: use role name join
        $technicians = $this->db->table('users u')
            ->join('roles r','r.id=u.role_id')
            ->where('r.name','technician')
            ->where('u.status','active')
            ->select('u.*')->get()->getResultArray();

        $inventoryItems = $this->db->table('inventory_items')
            ->where('quantity >',0)->orderBy('name','ASC')->get()->getResultArray();

        return view('job_cards/create', $this->viewData([
            'title'          => 'Create Job Card',
            'preselectedWo'  => $wo,
            'workOrders'     => $workOrders,
            'technicians'    => $technicians,
            'inventoryItems' => $inventoryItems,
        ]));
    }

    public function store()
    {
        $rules = [
            'wo_id'       => 'required|integer',
            'assigned_to' => 'required|integer',
            'description' => 'required|min_length[10]|max_length[2000]',
        ];
        if (!$this->validate($rules)) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $jcNumber = $this->generateNumber('JC','job_cards','jc_number');
        $this->db->table('job_cards')->insert([
            'jc_number'   => $jcNumber,
            'wo_id'       => (int)$this->request->getPost('wo_id'),
            'assigned_to' => (int)$this->request->getPost('assigned_to'),
            'description' => esc($this->request->getPost('description')),
            'status'      => 'draft',
            'created_by'  => session()->get('user_id'),
        ]);
        $jcId = $this->db->insertID();

        // Notify assigned technician
        $tech = $this->db->table('users')->where('id', (int)$this->request->getPost('assigned_to'))->get()->getRowArray();
        if ($tech) {
            $this->db->table('notifications')->insert([
                'user_id'      => $tech['id'],
                'title'        => "Job Card Assigned: $jcNumber",
                'message'      => 'You have been assigned a new job card.',
                'type'         => 'job_card',
                'reference_id' => $jcId,
            ]);
        }

        $this->logActivity('create', 'job_cards', $jcId, "Created $jcNumber");
        return redirect()->to(base_url('job-cards/view/' . $jcId))
            ->with('success', "Job Card $jcNumber created.");
    }

    public function view(int $id)
    {
        $role = session()->get('user_role');
        $uid  = session()->get('user_id');

        $jc = $this->db->table('job_cards jc')
            ->select('jc.*, wo.wo_number, wo.title as wo_title, wo.description as wo_description,
                      wo.priority, wo.type, f.name as facility_name,
                      u.name as assigned_to_name, cu.name as created_by_name,
                      ap.name as approved_by_name')
            ->join('work_orders wo','wo.id=jc.wo_id','left')
            ->join('facilities f','f.id=wo.facility_id','left')
            ->join('users u','u.id=jc.assigned_to','left')
            ->join('users cu','cu.id=jc.created_by','left')
            ->join('users ap','ap.id=jc.approved_by','left')
            ->where('jc.id', $id)->get()->getRowArray();

        if (!$jc) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();

        // IDOR check for technicians
        if ($role === 'technician' && (int)$jc['assigned_to'] !== (int)$uid) {
            return redirect()->to(base_url('job-cards'))->with('error', 'Access denied.');
        }

        $materials = $this->db->table('jc_materials m')
            ->select('m.*, i.name as item_name, i.unit')
            ->join('inventory_items i','i.id=m.item_id','left')
            ->where('m.jc_id', $id)->get()->getResultArray();

        $attachments = $this->db->table('jc_attachments')
            ->where('jc_id', $id)->get()->getResultArray();

        $totalMaterialCost = array_sum(array_column($materials, 'total_cost'));
        $laborCost = (float)$jc['labor_hours'] * 25; // default rate

        $inventoryItems = $this->db->table('inventory_items')->where('quantity >',0)->get()->getResultArray();

        return view('job_cards/view', $this->viewData([
            'title'             => $jc['jc_number'],
            'jc'                => $jc,
            'materials'         => $materials,
            'attachments'       => $attachments,
            'totalMaterialCost' => $totalMaterialCost,
            'laborCost'         => $laborCost,
            'inventoryItems'    => $inventoryItems,
        ]));
    }

    public function edit(int $id)
    {
        $jc = $this->db->table('job_cards')->where('id', $id)->get()->getRowArray();
        if (!$jc) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        if (in_array($jc['status'], ['approved'])) {
            return redirect()->back()->with('error', 'Approved job cards cannot be edited.');
        }

        $workOrders  = $this->db->table('work_orders w')
            ->select('w.id, w.wo_number, w.title')
            ->whereIn('w.status',['assigned','in_progress'])
            ->get()->getResultArray();
        $technicians = $this->db->table('users u')
            ->join('roles r','r.id=u.role_id')
            ->where('r.name','technician')->where('u.status','active')
            ->select('u.*')->get()->getResultArray();

        return view('job_cards/edit', $this->viewData([
            'title'       => 'Edit ' . $jc['jc_number'],
            'jc'          => $jc,
            'workOrders'  => $workOrders,
            'technicians' => $technicians,
        ]));
    }

    public function update(int $id)
    {
        $jc = $this->db->table('job_cards')->where('id', $id)->get()->getRowArray();
        if (!$jc) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();

        $role = session()->get('user_role');
        $uid  = session()->get('user_id');
        if ($role === 'technician' && (int)$jc['assigned_to'] !== (int)$uid) {
            return redirect()->back()->with('error', 'Access denied.');
        }

        $status = $this->request->getPost('status');
        $update = [
            'description'      => esc($this->request->getPost('description')),
            'labor_hours'      => (float)($this->request->getPost('labor_hours') ?? 0),
            'completion_notes' => esc($this->request->getPost('completion_notes') ?? ''),
            'status'           => $status,
        ];

        if ($status === 'completed' && empty($jc['completed_at'])) {
            $update['completed_at'] = date('Y-m-d H:i:s');
        }

        // Handle before/after image uploads
        foreach (['before_image', 'after_image'] as $imgField) {
            $file = $this->request->getFile($imgField);
            if ($file && $file->isValid() && !$file->hasMoved()) {
                $allowed = ['image/jpeg','image/png','image/webp','image/gif'];
                if (in_array($file->getMimeType(), $allowed) && $file->getSize() <= 5*1024*1024) {
                    $dir = WRITEPATH . 'uploads/job_cards/';
                    if (!is_dir($dir)) mkdir($dir, 0755, true);
                    $name = bin2hex(random_bytes(12)) . '.' . $file->getExtension();
                    $file->move($dir, $name);
                    $update[$imgField] = 'uploads/job_cards/' . $name;
                }
            }
        }

        $this->db->table('job_cards')->where('id', $id)->update($update);
        $this->logActivity('update', 'job_cards', $id);
        return redirect()->to(base_url('job-cards/view/' . $id))->with('success', 'Job card updated.');
    }

    public function addMaterial(int $id)
    {
        $itemId   = (int)$this->request->getPost('item_id');
        $qty      = (float)($this->request->getPost('quantity') ?? 1);
        $unitCost = (float)($this->request->getPost('unit_cost') ?? 0);

        if ($itemId) {
            $inv = $this->db->table('inventory_items')->where('id', $itemId)->get()->getRowArray();
            if ($inv) {
                if ($inv['quantity'] < $qty) {
                    return redirect()->back()->with('error', "Insufficient stock: {$inv['quantity']} {$inv['unit']} available.");
                }
                if ($unitCost <= 0) $unitCost = (float)$inv['unit_cost'];

                $this->db->table('inventory_items')->where('id', $itemId)
                    ->update(['quantity' => $inv['quantity'] - $qty]);
                $this->db->table('stock_movements')->insert([
                    'item_id'       => $itemId,
                    'movement_type' => 'out',
                    'quantity'      => (int)$qty,
                    'reference'     => 'JC-' . $id,
                    'notes'         => 'Used in job card',
                    'created_by'    => session()->get('user_id'),
                ]);
            }
        }

        $this->db->table('jc_materials')->insert([
            'jc_id'      => $id,
            'item_id'    => $itemId ?: null,
            'item_name'  => esc($this->request->getPost('item_name') ?? ($inv['name'] ?? '')),
            'quantity'   => $qty,
            'unit_cost'  => $unitCost,
            'total_cost' => $qty * $unitCost,
        ]);

        return redirect()->to(base_url('job-cards/view/' . $id))->with('success', 'Material added to job card.');
    }

    public function approve(int $id)
    {
        $this->requireRole('super_admin', 'facility_manager');
        $jc = $this->db->table('job_cards')->where('id', $id)->get()->getRowArray();
        if (!$jc) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        if ($jc['status'] !== 'completed') {
            return redirect()->back()->with('error', 'Only completed job cards can be approved.');
        }
        $this->db->table('job_cards')->where('id', $id)->update([
            'status'      => 'approved',
            'approved_by' => session()->get('user_id'),
            'approved_at' => date('Y-m-d H:i:s'),
        ]);
        $this->logActivity('approve', 'job_cards', $id);
        return redirect()->to(base_url('job-cards/view/' . $id))->with('success', 'Job card approved.');
    }

    public function printView(int $id)
    {
        $jc = $this->db->table('job_cards jc')
            ->select('jc.*, wo.wo_number, wo.title as wo_title, wo.description as wo_description,
                      wo.priority, f.name as facility_name,
                      u.name as assigned_to_name')
            ->join('work_orders wo','wo.id=jc.wo_id','left')
            ->join('facilities f','f.id=wo.facility_id','left')
            ->join('users u','u.id=jc.assigned_to','left')
            ->where('jc.id', $id)->get()->getRowArray();

        if (!$jc) throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();

        $materials = $this->db->table('jc_materials m')
            ->select('m.*, i.name as item_name, i.unit')
            ->join('inventory_items i','i.id=m.item_id','left')
            ->where('m.jc_id', $id)->get()->getResultArray();

        return view('job_cards/print', $this->viewData([
            'title'     => 'Print: ' . $jc['jc_number'],
            'jc'        => $jc,
            'materials' => $materials,
            'usePdf'    => true,
        ]));
    }
}
