<?php
declare(strict_types=1);

namespace App\Controllers\Web;

use App\Middleware\AuthSession;
use App\Middleware\TenantScope;
use App\Models\Asset;
use App\Models\AssetType;
use App\Models\PmTemplate;
use App\Models\User;
use App\Models\WorkOrder;
use Core\Controller;
use Core\DB;
use Core\Session;
use Core\Tool;

/**
 * Ad-hoc checklist flow — Field Techs and PMs browse the list of published
 * PM templates (a.k.a. checklists in the legacy vocabulary) and start filling
 * one out on demand:
 *
 *   /Checklists                    → list active templates
 *   /Checklists/start/{templateId} → pick asset + optional notes
 *   POST /Checklists/create        → creates a WO + tasks from the template,
 *                                    redirects to /WorkOrders/show/{id} to fill in.
 *
 * The scheduled `pm:generate` command still works for pre-planned automatic
 * PMs — this controller is for on-the-spot execution.
 */
final class ChecklistsController extends Controller
{
    public function middleware(): array
    {
        return [AuthSession::class, TenantScope::class];
    }

    private function tenantId(): int { return (int) ($_SESSION['tenant_id'] ?? 0); }

    public function index(): void
    {
        $tenantId = $this->tenantId();

        // Only active templates that have at least one task (blank checklists
        // aren't useful for the tech).
        $templates = DB::all(
            "SELECT t.*, at.name AS asset_type_name, at.code AS asset_type_code, at.color,
                    (SELECT COUNT(*) FROM pm_template_tasks tt WHERE tt.template_id = t.template_id) AS task_count
               FROM pm_templates t
          LEFT JOIN asset_types at ON at.asset_type_id = t.asset_type_id
              WHERE t.tenant_id = :t AND t.deleted_at IS NULL AND t.is_active = 1
              ORDER BY t.interval_days, t.name",
            ['t' => $tenantId]
        );

        $this->render('checklists/index', [
            'title'     => 'Available Checklists',
            'templates' => $templates,
            'flash'     => Session::flash('checklists_msg'),
        ]);
    }

    public function start(int $templateId): void
    {
        $tenantId = $this->tenantId();
        $userId   = (int) (Session::user()['user_id'] ?? 0);
        $tpl = PmTemplate::findInTenant($tenantId, $templateId);
        if (!$tpl || !$tpl['is_active']) {
            Session::flash('checklists_msg', 'Checklist not available.');
            redirect('/Checklists');
        }

        $users = User::listForTenant($tenantId);

        // Check for an existing in-progress WO for this template by this user.
        $existingWo = WorkOrder::findInProgressByTemplate($tenantId, $templateId, $userId);
        if ($existingWo) {
            $this->render('checklists/start', [
                'title'        => 'Start: ' . $tpl['name'],
                'template'     => $tpl,
                'assetType'    => $tpl['asset_type_id'] ? AssetType::findInTenant($tenantId, (int) $tpl['asset_type_id']) : null,
                'assets'       => [],
                'users'        => $users,
                'tasks'        => PmTemplate::tasksFor($templateId),
                'csrf'         => Tool::generateCsrf(),
                'flash'        => Session::flash('checklists_msg'),
                'existingWo'   => $existingWo,
                'existingWoUrl'=> url('/WorkOrders/show/' . (int) $existingWo['work_order_id']),
            ]);
            return;
        }

        // If the template targets a specific asset type, filter the picker.
        $assets = $tpl['asset_type_id']
            ? DB::all(
                "SELECT asset_id, name FROM assets
                  WHERE tenant_id = :t AND deleted_at IS NULL AND status = 'active'
                    AND asset_type_id = :at
                  ORDER BY name",
                ['t' => $tenantId, 'at' => (int) $tpl['asset_type_id']]
            )
            : Asset::optionsForTenant($tenantId);

        $tasks = PmTemplate::tasksFor($templateId);

        $this->render('checklists/start', [
            'title'        => 'Start: ' . $tpl['name'],
            'template'     => $tpl,
            'assetType'    => $tpl['asset_type_id'] ? AssetType::findInTenant($tenantId, (int) $tpl['asset_type_id']) : null,
            'assets'       => $assets,
            'users'        => $users,
            'tasks'        => $tasks,
            'csrf'         => Tool::generateCsrf(),
            'flash'        => Session::flash('checklists_msg'),
            'existingWo'   => null,
            'existingWoUrl'=> null,
        ]);
    }

    /**
     * Creates a work order + tasks from a template, then redirects to the
     * WO show page so the tech can start filling it in.
     */
    public function create(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') redirect('/Checklists');
        if (!Tool::checkCsrf($_POST['_csrf'] ?? null)) {
            Session::flash('checklists_msg', 'Session expired.'); redirect('/Checklists');
        }

        $tenantId   = $this->tenantId();
        $userId     = (int) (Session::user()['user_id'] ?? 0);
        $templateId = (int) ($_POST['template_id'] ?? 0);
        $assetId    = (int) ($_POST['asset_id']    ?? 0);
        $notes      = trim((string) ($_POST['notes'] ?? '')) ?: null;
        $assignTo   = (int) ($_POST['assigned_to'] ?? 0);

        // Validate assigned_to user exists in tenant; fallback to current user.
        $assignedUserId = $userId;
        if ($assignTo > 0 && $assignTo !== $userId) {
            $assignee = User::findByIdInTenant($tenantId, $assignTo);
            if ($assignee && ($assignee['status'] ?? '') === 'active') {
                $assignedUserId = $assignTo;
            }
        }

        $tpl = PmTemplate::findInTenant($tenantId, $templateId);
        if (!$tpl || !$tpl['is_active']) {
            Session::flash('checklists_msg', 'Checklist not available.');
            redirect('/Checklists');
        }

        // Asset is required IF the template is asset-type-scoped; else optional.
        if ($tpl['asset_type_id'] && $assetId <= 0) {
            Session::flash('checklists_msg', 'Please pick the asset this checklist covers.');
            redirect('/Checklists/start/' . $templateId);
        }
        if ($assetId > 0) {
            $asset = Asset::findInTenant($tenantId, $assetId);
            if (!$asset) {
                Session::flash('checklists_msg', 'Asset not found.');
                redirect('/Checklists/start/' . $templateId);
            }
            // If the template targets a specific type, the asset must match.
            if ($tpl['asset_type_id'] && (int) $asset['asset_type_id'] !== (int) $tpl['asset_type_id']) {
                Session::flash('checklists_msg', 'That asset is not the right type for this checklist.');
                redirect('/Checklists/start/' . $templateId);
            }
        }

        // Build the WO in one transaction so orphan tasks can't happen if the
        // template has 20 items and we die mid-loop.
        $woId = DB::tx(function () use ($tenantId, $userId, $assignedUserId, $tpl, $assetId, $notes, $templateId) {
            $now = date('Y-m-d H:i:s');
            $id = WorkOrder::create($tenantId, $userId, [
                'title'        => 'Checklist: ' . $tpl['name'],
                'description'  => $tpl['description'] ?? null,
                'wo_type'      => 'preventive',
                'priority'     => $tpl['priority'] ?? 'medium',
                'status'       => 'in_progress',
                'asset_id'     => $assetId > 0 ? $assetId : null,
                'assigned_to'  => $assignedUserId,
                'scheduled_at' => $now,
                'due_at'       => $now,
                'notes'        => $notes,
            ]);
            foreach (PmTemplate::tasksFor($templateId) as $t) {
                WorkOrder::addTask($id, [
                    'title'        => $t['title'],
                    'description'  => $t['description'],
                    'sort_order'   => (int) $t['sort_order'],
                    'input_type'   => $t['input_type']   ?? 'checkbox',
                    'options_json' => $t['options_json'] ?? null,
                    'is_required'  => !empty($t['is_required']),
                ]);
            }
            // Mark started_at now so the reporting shows it as in-flight.
            DB::run(
                'UPDATE work_orders SET started_at = NOW() WHERE work_order_id = :id',
                ['id' => $id]
            );
            return $id;
        });

        Session::flash('wo_msg', 'Checklist started. Fill in each item below, then close the WO when done.');
        redirect('/WorkOrders/show/' . $woId);
    }
}
