<?php

namespace Modules\Operations\Controllers;

use App\Controllers\BaseController;
use App\Models\CompanyModel;
use App\Models\EmployeeModel;
use App\Models\FsServiceVisitModel;
use App\Models\QcAuditChecklistItemModel;
use App\Models\QcAuditChecklistModel;
use App\Models\QcInspectionModel;
use App\Models\QcPerformanceScoreModel;
use App\Models\WorkOrderModel;
use Modules\Operations\Services\QualityControlService;

class QualityControlController extends BaseController
{
    protected QcInspectionModel $inspections;
    protected QcAuditChecklistModel $checklists;
    protected QcAuditChecklistItemModel $checklistItems;
    protected QcPerformanceScoreModel $scores;
    protected QualityControlService $service;
    protected EmployeeModel $employees;
    protected CompanyModel $companies;
    protected WorkOrderModel $workOrders;
    protected FsServiceVisitModel $serviceVisits;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->inspections    = new QcInspectionModel();
        $this->checklists     = new QcAuditChecklistModel();
        $this->checklistItems = new QcAuditChecklistItemModel();
        $this->scores         = new QcPerformanceScoreModel();
        $this->service        = new QualityControlService();
        $this->employees      = new EmployeeModel();
        $this->companies      = new CompanyModel();
        $this->workOrders     = new WorkOrderModel();
        $this->serviceVisits  = new FsServiceVisitModel();
    }

    // -------------------------------------------------------------------------
    // Inspections
    // -------------------------------------------------------------------------

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

        $entries = $this->inspections
            ->scopeForList($search ?: null, $status, $priority, $result)
            ->orderBy('qc_inspections.scheduled_date', 'ASC')
            ->orderBy('qc_inspections.id', 'DESC')
            ->paginate(25);

        return view('Modules\Operations\Views\quality_control\inspections\index', array_merge($this->baseViewData(), [
            'title'   => 'Inspections',
            'entries' => $entries,
            'pager'   => $this->inspections->pager,
            'filters' => compact('search', 'status', 'priority', 'result'),
        ]));
    }

    public function createForm()
    {
        return view('Modules\Operations\Views\quality_control\inspections\create', array_merge($this->baseViewData(), [
            'title'         => 'Create Inspection',
            'inspection'    => [],
            'employees'     => $this->employees->scopeForList(null, 'active')->orderBy('full_name', 'ASC')->findAll(),
            'companies'     => $this->companies->scopeForList(null, 'active')->orderBy('name', 'ASC')->findAll(),
            'workOrders'    => $this->workOrders->getAssignable(),
            'serviceVisits' => $this->serviceVisits->getOpenForSelect(),
        ]));
    }

    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[planned,in_progress]',
            'overall_result'        => 'permit_empty|in_list[pass,fail,na,pending]',
            'scheduled_date'        => 'permit_empty|valid_date',
            'inspector_employee_id' => 'permit_empty|is_natural_no_zero',
            'company_id'            => 'permit_empty|is_natural_no_zero',
            'work_order_id'         => 'permit_empty|is_natural_no_zero',
            'service_visit_id'      => 'permit_empty|is_natural_no_zero',
            'score'                 => 'permit_empty|decimal',
            'location'              => 'permit_empty|max_length[200]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

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

        return redirect()->to('/operations/quality-control/inspections/' . $result['id'])
            ->with('success', 'Inspection created.');
    }

    public function show(int $id)
    {
        $inspection = $this->inspections->scopeForList()->where('qc_inspections.id', $id)->first();
        if (! $inspection) {
            return redirect()->to('/operations/quality-control/inspections')->with('error', 'Inspection not found.');
        }

        return view('Modules\Operations\Views\quality_control\inspections\show', array_merge($this->baseViewData(), [
            'title'      => $inspection['number'],
            'inspection' => $inspection,
        ]));
    }

    public function editForm(int $id)
    {
        $inspection = $this->inspections->find($id);
        if (! $inspection) {
            return redirect()->to('/operations/quality-control/inspections')->with('error', 'Inspection not found.');
        }

        if (! in_array($inspection['status'], QcInspectionModel::OPEN_STATUSES, true)) {
            return redirect()->to('/operations/quality-control/inspections/' . $id)
                ->with('error', 'Only open inspections can be edited.');
        }

        return view('Modules\Operations\Views\quality_control\inspections\edit', array_merge($this->baseViewData(), [
            'title'         => 'Edit Inspection',
            'inspection'    => $inspection,
            'employees'     => $this->employees->scopeForList(null, 'active')->orderBy('full_name', 'ASC')->findAll(),
            'companies'     => $this->companies->scopeForList(null, 'active')->orderBy('name', 'ASC')->findAll(),
            'workOrders'    => $this->workOrders->getAssignable(),
            'serviceVisits' => $this->serviceVisits->getOpenForSelect(),
        ]));
    }

    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]',
            'status'                => 'permit_empty|in_list[planned,in_progress]',
            'overall_result'        => 'permit_empty|in_list[pass,fail,na,pending]',
            'scheduled_date'        => 'permit_empty|valid_date',
            'inspector_employee_id' => 'permit_empty|is_natural_no_zero',
            'company_id'            => 'permit_empty|is_natural_no_zero',
            'work_order_id'         => 'permit_empty|is_natural_no_zero',
            'service_visit_id'      => 'permit_empty|is_natural_no_zero',
            'score'                 => 'permit_empty|decimal',
            'location'              => 'permit_empty|max_length[200]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->updateInspection($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/quality-control/inspections/' . $id)->with('success', 'Inspection updated.');
    }

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

        return redirect()->to('/operations/quality-control/inspections/' . $id)->with('success', 'Inspection completed.');
    }

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

        return redirect()->to('/operations/quality-control/inspections/' . $id)->with('success', 'Inspection cancelled.');
    }

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

        return redirect()->to('/operations/quality-control/inspections')->with('success', 'Inspection deleted.');
    }

    // -------------------------------------------------------------------------
    // Audit checklists
    // -------------------------------------------------------------------------

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

        $entries = $this->checklists
            ->scopeForList($search ?: null, $status)
            ->orderBy('qc_audit_checklists.id', 'DESC')
            ->paginate(25);

        return view('Modules\Operations\Views\quality_control\audit_checklists\index', array_merge($this->baseViewData(), [
            'title'   => 'Audit Checklists',
            'entries' => $entries,
            'pager'   => $this->checklists->pager,
            'filters' => compact('search', 'status'),
        ]));
    }

    public function createChecklistForm()
    {
        return view('Modules\Operations\Views\quality_control\audit_checklists\create', array_merge($this->baseViewData(), [
            'title'     => 'Create Audit Checklist',
            'checklist' => [],
        ]));
    }

    public function storeChecklist()
    {
        if (! $this->validate([
            'name'   => 'required|min_length[2]|max_length[200]',
            'code'   => 'permit_empty|max_length[50]',
            'status' => 'permit_empty|in_list[active,inactive]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

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

        return redirect()->to('/operations/quality-control/audit-checklists/' . $result['id'])
            ->with('success', 'Audit checklist created.');
    }

    public function showChecklist(int $id)
    {
        $checklist = $this->checklists->find($id);
        if (! $checklist) {
            return redirect()->to('/operations/quality-control/audit-checklists')->with('error', 'Checklist not found.');
        }

        return view('Modules\Operations\Views\quality_control\audit_checklists\show', array_merge($this->baseViewData(), [
            'title'     => $checklist['number'],
            'checklist' => $checklist,
            'items'     => $this->checklistItems->getForChecklist($id),
        ]));
    }

    public function editChecklistForm(int $id)
    {
        $checklist = $this->checklists->find($id);
        if (! $checklist) {
            return redirect()->to('/operations/quality-control/audit-checklists')->with('error', 'Checklist not found.');
        }

        return view('Modules\Operations\Views\quality_control\audit_checklists\edit', array_merge($this->baseViewData(), [
            'title'     => 'Edit Audit Checklist',
            'checklist' => $checklist,
        ]));
    }

    public function updateChecklist(int $id)
    {
        if (! $this->validate([
            'name'   => 'required|min_length[2]|max_length[200]',
            'code'   => 'permit_empty|max_length[50]',
            'status' => 'permit_empty|in_list[active,inactive]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->updateChecklist($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/quality-control/audit-checklists/' . $id)
            ->with('success', 'Audit checklist updated.');
    }

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

        return redirect()->to('/operations/quality-control/audit-checklists')
            ->with('success', 'Audit checklist deleted.');
    }

    public function addChecklistItem()
    {
        if (! $this->validate([
            'checklist_id' => 'required|is_natural_no_zero',
            'title'        => 'required|min_length[1]|max_length[255]',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

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

        return redirect()->to('/operations/quality-control/audit-checklists/' . $checklistId)
            ->with('success', 'Checklist item added.');
    }

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

        $redirect = ! empty($result['checklist_id'])
            ? '/operations/quality-control/audit-checklists/' . $result['checklist_id']
            : '/operations/quality-control/audit-checklists';

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

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

        $redirect = ! empty($result['checklist_id'])
            ? '/operations/quality-control/audit-checklists/' . $result['checklist_id']
            : '/operations/quality-control/audit-checklists';

        return redirect()->to($redirect)->with('success', 'Checklist item updated.');
    }

    // -------------------------------------------------------------------------
    // Performance scores
    // -------------------------------------------------------------------------

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

        $entries = $this->scores
            ->scopeForList($search ?: null, $status, $subjectType)
            ->orderBy('qc_performance_scores.id', 'DESC')
            ->paginate(25);

        return view('Modules\Operations\Views\quality_control\performance_scores\index', array_merge($this->baseViewData(), [
            'title'   => 'Performance Scores',
            'entries' => $entries,
            'pager'   => $this->scores->pager,
            'filters' => compact('search', 'status', 'subjectType'),
        ]));
    }

    public function createScoreForm()
    {
        return view('Modules\Operations\Views\quality_control\performance_scores\create', array_merge($this->baseViewData(), [
            'title'     => 'Create Performance Score',
            'score'     => [],
            'employees' => $this->employees->scopeForList(null, 'active')->orderBy('full_name', 'ASC')->findAll(),
        ]));
    }

    public function storeScore()
    {
        if (! $this->validate([
            'subject_type'  => 'required|in_list[employee,work_order,service_visit,inspection]',
            'subject_id'    => 'required|is_natural_no_zero',
            'subject_label' => 'permit_empty|max_length[200]',
            'metric_code'   => 'required|min_length[1]|max_length[80]',
            'metric_name'   => 'required|min_length[1]|max_length[150]',
            'score'         => 'permit_empty|decimal',
            'max_score'     => 'permit_empty|decimal',
            'period_start'  => 'permit_empty|valid_date',
            'period_end'    => 'permit_empty|valid_date',
            'scored_by'     => 'permit_empty|is_natural_no_zero',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

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

        return redirect()->to('/operations/quality-control/performance-scores/' . $result['id'])
            ->with('success', 'Performance score created.');
    }

    public function showScore(int $id)
    {
        $score = $this->scores->scopeForList()->where('qc_performance_scores.id', $id)->first();
        if (! $score) {
            return redirect()->to('/operations/quality-control/performance-scores')->with('error', 'Performance score not found.');
        }

        return view('Modules\Operations\Views\quality_control\performance_scores\show', array_merge($this->baseViewData(), [
            'title' => $score['number'],
            'score' => $score,
        ]));
    }

    public function editScoreForm(int $id)
    {
        $score = $this->scores->find($id);
        if (! $score) {
            return redirect()->to('/operations/quality-control/performance-scores')->with('error', 'Performance score not found.');
        }

        if ($score['status'] !== 'draft') {
            return redirect()->to('/operations/quality-control/performance-scores/' . $id)
                ->with('error', 'Only draft scores can be edited.');
        }

        return view('Modules\Operations\Views\quality_control\performance_scores\edit', array_merge($this->baseViewData(), [
            'title'     => 'Edit Performance Score',
            'score'     => $score,
            'employees' => $this->employees->scopeForList(null, 'active')->orderBy('full_name', 'ASC')->findAll(),
        ]));
    }

    public function updateScore(int $id)
    {
        if (! $this->validate([
            'subject_type'  => 'required|in_list[employee,work_order,service_visit,inspection]',
            'subject_id'    => 'required|is_natural_no_zero',
            'subject_label' => 'permit_empty|max_length[200]',
            'metric_code'   => 'required|min_length[1]|max_length[80]',
            'metric_name'   => 'required|min_length[1]|max_length[150]',
            'score'         => 'permit_empty|decimal',
            'max_score'     => 'permit_empty|decimal',
            'period_start'  => 'permit_empty|valid_date',
            'period_end'    => 'permit_empty|valid_date',
            'scored_by'     => 'permit_empty|is_natural_no_zero',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->updateScore($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/quality-control/performance-scores/' . $id)
            ->with('success', 'Performance score updated.');
    }

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

        return redirect()->to('/operations/quality-control/performance-scores/' . $id)
            ->with('success', 'Performance score published.');
    }

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

        return redirect()->to('/operations/quality-control/performance-scores')
            ->with('success', 'Performance score deleted.');
    }
}
