<?php

namespace App\Controllers;

use App\Models\MaintenanceWorkOrderModel;
use App\Models\RoomModel;
use App\Models\UserModel;
use Config\Lookups;

/**
 * Maintenance module — built for real from a user-supplied mockup
 * (previously a disabled "Soon" nav item). The mockup's "Total Assets"
 * stat and asset picker, and its "Upcoming Maintenance" preventive-
 * schedule list, both implied a fixed-asset register with recurring
 * service schedules — real, materially bigger scope than reactive work
 * orders. Neither exists here; "Upcoming" below is real open work orders
 * sorted by due date instead, and there's no asset count to show.
 */
class MaintenanceController extends BaseController
{
    public function index()
    {
        $orders = new MaintenanceWorkOrderModel();

        $tab = $this->request->getGet('tab') ?: 'all';

        $builder = $orders->withDetails();

        switch ($tab) {
            case 'open':
                $builder->where('maintenance_work_orders.status', 'open');
                break;
            case 'in_progress':
                $builder->where('maintenance_work_orders.status', 'in_progress');
                break;
            case 'overdue':
                $builder->whereIn('maintenance_work_orders.status', ['open', 'in_progress'])
                    ->where('maintenance_work_orders.due_date IS NOT NULL', null, false)
                    ->where('maintenance_work_orders.due_date <', date('Y-m-d'));
                break;
            case 'completed':
                $builder->where('maintenance_work_orders.status', 'completed');
                break;
            case 'all':
            default:
                break;
        }

        $list = $builder->orderBy('maintenance_work_orders.created_at', 'desc')->findAll();

        $upcoming = (new MaintenanceWorkOrderModel())->withDetails()
            ->whereIn('maintenance_work_orders.status', ['open', 'in_progress'])
            ->where('maintenance_work_orders.due_date IS NOT NULL', null, false)
            ->orderBy('maintenance_work_orders.due_date', 'asc')
            ->limit(5)
            ->findAll();

        return view('maintenance/index', [
            'pageTitle'    => 'Maintenance',
            'pageSubtitle' => 'Manage and track maintenance requests and work orders.',
            'tab'          => $tab,
            'orders'       => $list,
            'upcoming'     => $upcoming,
            'stats'        => [
                'open'          => (new MaintenanceWorkOrderModel())->countByStatus('open'),
                'inProgress'    => (new MaintenanceWorkOrderModel())->countByStatus('in_progress'),
                'completedToday' => (new MaintenanceWorkOrderModel())->countCompletedOn(date('Y-m-d')),
                'overdue'       => (new MaintenanceWorkOrderModel())->countOverdue(),
                'byPriority'    => [
                    'high'   => (new MaintenanceWorkOrderModel())->countByPriority('high'),
                    'medium' => (new MaintenanceWorkOrderModel())->countByPriority('medium'),
                    'low'    => (new MaintenanceWorkOrderModel())->countByPriority('low'),
                ],
            ],
            'lookups' => new Lookups(),
        ]);
    }

    public function new()
    {
        return view('maintenance/form', [
            'pageTitle' => 'New Work Order',
            'rooms'     => (new RoomModel())->withType()->orderBy('rooms.room_number')->findAll(),
            'staff'     => (new UserModel())->where('is_active', 1)->orderBy('full_name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    /**
     * "Suggest with AI" on the New Work Order form — staff types title +
     * notes, Claude suggests a priority (validated against the real
     * Lookups::taskPriorities enum below — a value Claude returns outside
     * that set is treated as a failed call, never silently accepted) and
     * a plain-language note on who should likely handle it. A suggestion
     * only: nothing here creates or modifies a work order, and the
     * priority select on the form stays fully editable after this fills
     * it in. No tools — this is pure text classification, nothing here
     * needs a live data lookup.
     */
    public function suggestTriage()
    {
        if (service('settings')->get('ai.maintenance_triage_enabled', '1') !== '1') {
            return $this->response->setJSON(['success' => false, 'error' => 'Maintenance triage is turned off — enable it under Settings > AI Features.', 'csrf_hash' => csrf_hash()]);
        }

        $title = trim((string) $this->request->getPost('title'));
        $notes = trim((string) $this->request->getPost('notes'));

        if ($title === '' && $notes === '') {
            return $this->response->setJSON(['success' => false, 'error' => 'Enter a title or notes first.', 'csrf_hash' => csrf_hash()]);
        }

        $priorities = array_keys((new Lookups())->taskPriorities);

        $systemPrompt = 'You triage hotel maintenance issues. Given a short title and free-text notes describing an '
            . 'issue, respond with ONLY a single JSON object (no markdown fences, no extra text) with exactly these '
            . 'keys: "priority" (one of: ' . implode(', ', $priorities) . '), "suggested_role" (a short plain-language '
            . 'suggestion of who should handle it, e.g. "Housekeeping", "External contractor (electrical)", '
            . '"Urgent — possible safety issue, notify manager immediately"), and "reasoning" (one short sentence). '
            . 'This is a suggestion a staff member will review and can override — never claim certainty you don\'t have.';

        $result = service('claudeService')->chat(
            'maintenance_triage',
            $systemPrompt,
            [['role' => 'user', 'content' => "Title: {$title}\nNotes: {$notes}"]],
            [],
            null,
            'maintenance_work_order',
            null,
            $this->currentUserId(),
        );

        if (! $result['success']) {
            return $this->response->setJSON(['success' => false, 'error' => $result['error'], 'csrf_hash' => csrf_hash()]);
        }

        // Despite the system prompt's explicit "no markdown fences"
        // instruction, Claude sometimes wraps the JSON in a ```json ...```
        // fence anyway (confirmed live) — stripped defensively rather than
        // trusting the instruction was followed. Still just JSON parsing,
        // never a regex attempt to extract fields from prose.
        $text = trim((string) $result['text']);
        $text = preg_replace('/^```(?:json)?\s*|\s*```$/', '', $text);
        $parsed = json_decode($text, true);

        if (! is_array($parsed) || ! in_array($parsed['priority'] ?? null, $priorities, true)) {
            return $this->response->setJSON(['success' => false, 'error' => 'The AI response was not in the expected format — please set priority manually.', 'csrf_hash' => csrf_hash()]);
        }

        $this->logActivity('maintenance', 'Generated an AI triage suggestion for a new work order ("' . $title . '").');

        return $this->response->setJSON([
            'success'        => true,
            'priority'       => $parsed['priority'],
            'suggested_role' => $parsed['suggested_role'] ?? '',
            'reasoning'      => $parsed['reasoning'] ?? '',
            'csrf_hash'      => csrf_hash(),
        ]);
    }

    public function create()
    {
        $orders = new MaintenanceWorkOrderModel();

        $data = [
            'title'       => $this->request->getPost('title'),
            'asset'       => $this->request->getPost('asset') ?: null,
            'room_id'     => $this->request->getPost('room_id') ?: null,
            'priority'    => $this->request->getPost('priority') ?: 'medium',
            'assigned_to' => $this->request->getPost('assigned_to') ?: null,
            'due_date'    => $this->request->getPost('due_date') ?: null,
            'notes'       => $this->request->getPost('notes') ?: null,
            'status'      => 'open',
            'reported_by' => $this->currentUserId(),
        ];

        if (! $orders->insert($data)) {
            return $this->redirectWithModelErrors($orders);
        }

        $this->logActivity('maintenance', "Created work order \"{$data['title']}\".");

        return redirect()->to('maintenance')->with('success', 'Work order created.');
    }

    public function start(int $id)
    {
        $orders = new MaintenanceWorkOrderModel();

        if ($orders->find($id) === null) {
            return redirect()->to('maintenance')->with('error', 'Work order not found.');
        }

        $orders->update($id, ['status' => 'in_progress']);
        $this->logActivity('maintenance', "Started work order #{$id}.");

        return redirect()->to('maintenance')->with('success', 'Work order started.');
    }

    public function complete(int $id)
    {
        $orders = new MaintenanceWorkOrderModel();

        if ($orders->find($id) === null) {
            return redirect()->to('maintenance')->with('error', 'Work order not found.');
        }

        $orders->update($id, ['status' => 'completed', 'completed_at' => date('Y-m-d H:i:s')]);
        $this->logActivity('maintenance', "Completed work order #{$id}.");

        return redirect()->to('maintenance')->with('success', 'Work order completed.');
    }

    public function show(int $id)
    {
        $orders    = new MaintenanceWorkOrderModel();
        $workOrder = $orders->withDetails()->where('maintenance_work_orders.id', $id)->first();

        if ($workOrder === null) {
            return redirect()->to('maintenance')->with('error', 'Work order not found.');
        }

        return view('maintenance/show', [
            'pageTitle' => 'Work Order #' . $id,
            'workOrder' => $workOrder,
            'isOverdue' => $orders->isOverdue($workOrder),
            'lookups'   => new Lookups(),
        ]);
    }

    /**
     * Edits the reported details only (title/asset/room/priority/
     * assignee/due date/notes) — mirrors HousekeepingController::edit()'s
     * reasoning: status only ever moves forward through start()/
     * complete(), never hand-edited, so completed_at can't drift out of
     * sync with it.
     */
    public function edit(int $id)
    {
        $orders    = new MaintenanceWorkOrderModel();
        $workOrder = $orders->find($id);

        if ($workOrder === null) {
            return redirect()->to('maintenance')->with('error', 'Work order not found.');
        }

        return view('maintenance/form', [
            'pageTitle' => 'Edit Work Order',
            'workOrder' => $workOrder,
            'rooms'     => (new RoomModel())->withType()->orderBy('rooms.room_number')->findAll(),
            'staff'     => (new UserModel())->where('is_active', 1)->orderBy('full_name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    public function update(int $id)
    {
        $orders = new MaintenanceWorkOrderModel();

        if ($orders->find($id) === null) {
            return redirect()->to('maintenance')->with('error', 'Work order not found.');
        }

        $data = [
            'title'       => $this->request->getPost('title'),
            'asset'       => $this->request->getPost('asset') ?: null,
            'room_id'     => $this->request->getPost('room_id') ?: null,
            'priority'    => $this->request->getPost('priority') ?: 'medium',
            'assigned_to' => $this->request->getPost('assigned_to') ?: null,
            'due_date'    => $this->request->getPost('due_date') ?: null,
            'notes'       => $this->request->getPost('notes') ?: null,
        ];

        if (! $orders->update($id, $data)) {
            return $this->redirectWithModelErrors($orders);
        }

        $this->logActivity('maintenance', "Updated work order #{$id}.");

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