<?php
declare(strict_types=1);

namespace App\Controllers\Api;

use App\Middleware\ApiToken;
use App\Middleware\TenantScope;
use App\Models\Asset;
use App\Models\AssetType;
use App\Models\AssetTypeField;
use App\Models\Incident;
use App\Models\Site;
use App\Models\WorkOrder;
use Core\Controller;
use Core\DB;

/**
 * Single-shot delta pull for the mobile app.
 *
 *   GET /api/v1/sync/pull?since=2026-07-01T00:00:00
 *
 * Returns all entities the current user needs, filtered by tenant.
 * `since` is optional — omit for a cold-start full pull; provide for deltas.
 */
final class SyncController extends Controller
{
    public function middleware(): array
    {
        return [ApiToken::class, TenantScope::class];
    }

    public function pull(): void
    {
        $tenantId = (int) ($_SESSION['tenant_id'] ?? 0);
        $userId   = (int) ($_SESSION['user']['user_id'] ?? 0);
        $role     = $_SESSION['user']['role_code'] ?? '';
        $since    = trim((string) ($_GET['since'] ?? ''));
        $sinceExpr = $since !== '' ? " AND updated_at > :since" : '';
        $params = ['t' => $tenantId];
        if ($since !== '') { $params['since'] = str_replace('T', ' ', $since); }

        // Sites (all in tenant — small)
        try {
            $sites = DB::all(
                "SELECT * FROM sites WHERE tenant_id = :t AND deleted_at IS NULL{$sinceExpr}",
                $params
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] sites query failed: ' . $e->getMessage() . ' | params: ' . json_encode($params));
            throw $e;
        }

        // Asset types + fields (bundle together — few rows)
        try {
            $types = AssetType::optionsForTenant($tenantId);
            foreach ($types as &$t) {
                $t['fields'] = AssetTypeField::forType($tenantId, (int) $t['asset_type_id']);
            }
        } catch (\Throwable $e) {
            error_log('[SyncController] asset_types query failed: ' . $e->getMessage());
            throw $e;
        }

        // Assets — full list for tenant
        try {
            $assets = DB::all(
                "SELECT a.* FROM assets a WHERE a.tenant_id = :t AND a.deleted_at IS NULL{$sinceExpr}",
                $params
            );
            foreach ($assets as &$a) {
                if (!empty($a['meta_json'])) {
                    $decoded = json_decode($a['meta_json'], true);
                    if (is_array($decoded)) { $a['meta'] = $decoded; }
                }
            }
        } catch (\Throwable $e) {
            error_log('[SyncController] assets query failed: ' . $e->getMessage() . ' | params: ' . json_encode($params));
            throw $e;
        }

        // Work orders — techs get only their own, PMs+ get all
        $woSql = "SELECT * FROM work_orders WHERE tenant_id = :t AND deleted_at IS NULL{$sinceExpr}";
        $woParams = $params;
        if ($role === 'field_technician') {
            $woSql .= ' AND assigned_to = :u';
            $woParams['u'] = $userId;
        }
        try {
            $workOrders = DB::all($woSql, $woParams);
            foreach ($workOrders as &$w) {
                $w['tasks'] = WorkOrder::tasksFor((int) $w['work_order_id']);
            }
        } catch (\Throwable $e) {
            error_log('[SyncController] work_orders query failed: ' . $e->getMessage() . ' | params: ' . json_encode($woParams));
            throw $e;
        }

        // Incidents — techs see ones they reported or are assigned to; PMs+ get all
        $incSql = "SELECT * FROM incidents WHERE tenant_id = :t AND deleted_at IS NULL{$sinceExpr}";
        $incParams = $params;
        if ($role === 'field_technician') {
            $incSql .= ' AND (reported_by = :u1 OR assigned_to = :u2)';
            $incParams['u1'] = $userId;
            $incParams['u2'] = $userId;
        }
        try {
            $incidents = DB::all($incSql, $incParams);
        } catch (\Throwable $e) {
            error_log('[SyncController] incidents query failed: ' . $e->getMessage() . ' | params: ' . json_encode($incParams));
            throw $e;
        }

        // ── Reference data added for the new mobile features ──────────
        // Parts catalog (small set, tenant-wide) — mobile needs it for the
        // WO consumption picker and low-stock display.
        try {
            $parts = DB::all(
                "SELECT part_id, sku, name, unit, unit_cost, on_hand, min_stock, location, category, updated_at
                   FROM parts
                  WHERE tenant_id = :t AND deleted_at IS NULL AND is_active = 1{$sinceExpr}",
                $params
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] parts query failed: ' . $e->getMessage() . ' | params: ' . json_encode($params));
            throw $e;
        }

        // Round templates + their ordered stops. Two shapes: template rows and
        // a flat stops table the client can join in memory (no nested JSON so
        // SQLite can be its source of truth).
        try {
            $roundTemplates = DB::all(
                "SELECT round_template_id, tenant_id, name, description, frequency, is_active, updated_at
                   FROM round_templates
                  WHERE tenant_id = :t AND deleted_at IS NULL AND is_active = 1{$sinceExpr}",
                $params
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] round_templates query failed: ' . $e->getMessage() . ' | params: ' . json_encode($params));
            throw $e;
        }
        try {
            $roundStops = DB::all(
                'SELECT s.stop_id, s.round_template_id, s.asset_id, s.sort_order,
                        s.reading_key, s.reading_unit, s.min_ok, s.max_ok, s.instruction,
                        a.name AS asset_name
                   FROM round_template_stops s
                   JOIN round_templates rt ON rt.round_template_id = s.round_template_id
                   JOIN assets a           ON a.asset_id           = s.asset_id
                  WHERE rt.tenant_id = :t AND rt.deleted_at IS NULL AND rt.is_active = 1
                  ORDER BY s.round_template_id, s.sort_order',
                ['t' => $tenantId]
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] round_stops query failed: ' . $e->getMessage());
            throw $e;
        }

        // Permit types (very small — no `since` filter, always send all).
        try {
            $permitTypes = DB::all(
                'SELECT permit_type_id, code, name, description, icon
                   FROM permit_types
                  WHERE tenant_id = :t AND is_active = 1
                  ORDER BY name',
                ['t' => $tenantId]
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] permit_types query failed: ' . $e->getMessage());
            throw $e;
        }

        // PM Templates + tasks — the "checklists" layer (Daily Generator Check, etc.)
        try {
            $pmTemplates = DB::all(
                "SELECT template_id, tenant_id, asset_type_id, code, name, description,
                        interval_days, lead_days, priority, is_active, updated_at
                   FROM pm_templates
                  WHERE tenant_id = :t AND is_active = 1{$sinceExpr}
                  ORDER BY name",
                $params
            );
        } catch (\Throwable $e) {
            error_log('[SyncController] pm_templates query failed: ' . $e->getMessage() . ' | params: ' . json_encode($params));
            throw $e;
        }
        $pmTemplateTasks = [];
        if (!empty($pmTemplates)) {
            $tplIds = array_column($pmTemplates, 'template_id');
            $placeholders = implode(',', array_fill(0, count($tplIds), '?'));
            try {
                $pmTemplateTasks = DB::all(
                    "SELECT template_task_id, template_id, sort_order, title, description,
                            input_type, options_json, is_required
                       FROM pm_template_tasks
                      WHERE template_id IN ({$placeholders})
                      ORDER BY template_id, sort_order",
                    $tplIds
                );
            } catch (\Throwable $e) {
                error_log('[SyncController] pm_template_tasks query failed: ' . $e->getMessage() . ' | tplIds count: ' . count($tplIds));
                throw $e;
            }
        }

        $this->json([
            'server_time' => date('c'),
            'tenant_id'   => $tenantId,
            'data' => [
                'sites'              => $sites,
                'asset_types'        => $types,
                'assets'             => $assets,
                'work_orders'        => $workOrders,
                'incidents'          => $incidents,
                'parts'              => $parts,
                'round_templates'    => $roundTemplates,
                'round_stops'        => $roundStops,
                'permit_types'       => $permitTypes,
                'pm_templates'       => $pmTemplates,
                'pm_template_tasks'  => $pmTemplateTasks,
            ],
        ]);
    }
}
