<?php

namespace App\Controllers;

use App\Models\BlockchainTransactionModel;
use App\Models\MaintenanceEventModel;
use App\Models\MaintenanceInterventionModel;
use App\Models\OrganizationModel;
use App\Models\SiteModel;
use App\Models\TurbineModel;

class Demo extends BaseController
{
    private const BASE_RUNTIME_HOURS = 48231.7;
    private const ORG_SLUG = 'quantum-demo-wind';
    private const SITE_CODE = 'QTM-WF-DEMO-10M';
    private const TURBINE_CODE = 'QTM-TUR-DEMO-10M';
    private const DEFAULT_START = '2026-03-25 09:00:00';

    public function meter()
    {
        return view('demo/meter', [
            'pageTitle' => 'Quantum Demo | Simulador de manutencao',
            'demoState' => $this->demoSnapshot(),
        ]);
    }

    public function communicate()
    {
        $payload = $this->request->getJSON(true) ?: $this->request->getPost();
        $energyKwh = round((float) ($payload['energy_kwh'] ?? 0), 1);
        $sourceReference = trim((string) ($payload['source_reference'] ?? ''));

        if ($energyKwh <= 0) {
            return $this->response->setStatusCode(422)->setJSON([
                'ok' => false,
                'message' => 'O impacto tecnico tem de ser superior a zero.',
            ]);
        }

        $assets = $this->ensureDemoAssets();
        $slot = $this->nextSlot(
            (int) $assets['organization']['id'],
            (int) $assets['site']['id'],
            (int) $assets['turbine']['id']
        );

        $reference = $sourceReference !== '' ? $sourceReference : sprintf('EVT-DEMO-%04d', (int) $slot['sequence']);
        $interventionCode = sprintf('MI-DEMO-%04d', (int) $slot['sequence']);
        $title = sprintf('Demo technical intervention %04d', (int) $slot['sequence']);
        $anchoredHash = hash('sha256', implode('|', [
            $interventionCode,
            $reference,
            number_format($energyKwh, 1, '.', ''),
            $slot['start'],
            $slot['end'],
        ]));

        $interventions = new MaintenanceInterventionModel();
        $events = new MaintenanceEventModel();
        $transactions = new BlockchainTransactionModel();

        $interventionId = $interventions->insert([
            'organization_id' => (int) $assets['organization']['id'],
            'site_id' => (int) $assets['site']['id'],
            'turbine_id' => (int) $assets['turbine']['id'],
            'intervention_code' => $interventionCode,
            'title' => $title,
            'description' => 'Demo intervention generated from the public Quantum maintenance simulator.',
            'intervention_type' => 'inspection',
            'maintenance_mode' => 'condition_based',
            'priority' => 'medium',
            'status' => 'completed',
            'reported_at' => $slot['start'],
            'scheduled_start_at' => $slot['start'],
            'scheduled_end_at' => $slot['end'],
            'started_at' => $slot['start'],
            'completed_at' => $slot['end'],
            'created_by_user_id' => null,
            'assigned_to_user_id' => null,
            'external_reference' => $reference,
        ], true);

        $events->insert([
            'maintenance_intervention_id' => (int) $interventionId,
            'event_type' => 'demo_interval_registered',
            'event_message' => 'Demo maintenance interval registered and validated for audit.',
            'event_data' => json_encode([
                'source_reference' => $reference,
                'energy_kwh' => $energyKwh,
                'interval_start' => $slot['start'],
                'interval_end' => $slot['end'],
                'site_code' => self::SITE_CODE,
                'turbine_code' => self::TURBINE_CODE,
            ], JSON_UNESCAPED_SLASHES),
            'happened_at' => $slot['end'],
            'created_by_user_id' => null,
        ]);

        $transactionHash = '0x' . substr(hash('sha256', 'quantum-demo-tx|' . $anchoredHash), 0, 64);
        $transactions->insert([
            'maintenance_intervention_id' => (int) $interventionId,
            'network' => 'polygon-pos',
            'transaction_hash' => $transactionHash,
            'contract_address' => '0x' . substr(hash('sha256', 'quantum-demo-contract'), 0, 40),
            'block_number' => 56124000 + (int) $slot['sequence'],
            'status' => 'confirmed',
            'anchor_type' => 'intervention',
            'anchored_hash' => $anchoredHash,
        ]);

        return $this->response->setJSON([
            'ok' => true,
            'message' => 'Evento registado e auditoria gerada com sucesso na empresa demo.',
            'result' => [
                'energy_kwh' => $energyKwh,
                'source_reference' => $reference,
                'period_start' => $slot['start'],
                'period_end' => $slot['end'],
                'public_id' => $interventionCode,
                'reference_code' => $reference,
                'show_url' => site_url('maintenance/' . rawurlencode($interventionCode)),
                'verify_url' => site_url('audit?q=' . rawurlencode($interventionCode)),
            ],
            'state' => $this->demoSnapshot(),
        ]);
    }

    private function demoSnapshot(): array
    {
        $assets = $this->ensureDemoAssets();
        $organizationId = (int) $assets['organization']['id'];
        $siteId = (int) $assets['site']['id'];
        $turbineId = (int) $assets['turbine']['id'];

        $interventionRows = db_connect()->table('maintenance_interventions')
            ->select(
                'maintenance_interventions.id, maintenance_interventions.intervention_code,' .
                ' maintenance_interventions.external_reference, maintenance_interventions.scheduled_start_at,' .
                ' maintenance_interventions.scheduled_end_at, maintenance_interventions.created_at,' .
                ' blockchain_transactions.anchored_hash'
            )
            ->join(
                'blockchain_transactions',
                'blockchain_transactions.maintenance_intervention_id = maintenance_interventions.id',
                'left'
            )
            ->where('maintenance_interventions.organization_id', $organizationId)
            ->where('maintenance_interventions.site_id', $siteId)
            ->where('maintenance_interventions.turbine_id', $turbineId)
            ->like('maintenance_interventions.intervention_code', 'MI-DEMO-', 'after')
            ->orderBy('maintenance_interventions.scheduled_start_at', 'DESC')
            ->get()
            ->getResultArray();

        $eventRows = db_connect()->table('maintenance_events')
            ->select('maintenance_events.*, maintenance_interventions.intervention_code')
            ->join(
                'maintenance_interventions',
                'maintenance_interventions.id = maintenance_events.maintenance_intervention_id'
            )
            ->where('maintenance_interventions.organization_id', $organizationId)
            ->where('maintenance_interventions.site_id', $siteId)
            ->where('maintenance_interventions.turbine_id', $turbineId)
            ->where('maintenance_events.event_type', 'demo_interval_registered')
            ->orderBy('maintenance_events.happened_at', 'DESC')
            ->get()
            ->getResultArray();

        $eventDataByIntervention = [];
        $latestReadings = [];
        $totalEnergy = 0.0;

        foreach ($eventRows as $eventRow) {
            $payload = json_decode((string) ($eventRow['event_data'] ?? ''), true);
            if (! is_array($payload)) {
                $payload = [];
            }

            $energy = round((float) ($payload['energy_kwh'] ?? 0), 1);
            $totalEnergy += $energy;
            $eventDataByIntervention[(int) $eventRow['maintenance_intervention_id']] = $payload + ['energy_kwh' => $energy];

            if (count($latestReadings) < 6) {
                $latestReadings[] = [
                    'source_reference' => $payload['source_reference'] ?? $eventRow['intervention_code'],
                    'interval_start' => $payload['interval_start'] ?? $eventRow['happened_at'],
                    'interval_end' => $payload['interval_end'] ?? $eventRow['happened_at'],
                    'value_kwh' => $energy,
                    'created_at' => $eventRow['created_at'],
                ];
            }
        }

        $latestInterventions = [];
        foreach (array_slice($interventionRows, 0, 6) as $interventionRow) {
            $eventData = $eventDataByIntervention[(int) $interventionRow['id']] ?? [];
            $latestInterventions[] = [
                'public_id' => $interventionRow['intervention_code'],
                'reference_code' => $interventionRow['external_reference'] ?: $interventionRow['intervention_code'],
                'period_start' => $interventionRow['scheduled_start_at'],
                'period_end' => $interventionRow['scheduled_end_at'],
                'energy_kwh' => round((float) ($eventData['energy_kwh'] ?? 0), 1),
                'record_hash' => $interventionRow['anchored_hash'] ?? hash('sha256', $interventionRow['intervention_code']),
                'created_at' => $interventionRow['created_at'],
            ];
        }

        $slot = $this->nextSlot($organizationId, $siteId, $turbineId);
        $latestIntervention = $latestInterventions[0] ?? null;
        $latestReading = $latestReadings[0] ?? null;

        return [
            'base_meter_kwh' => self::BASE_RUNTIME_HOURS,
            'total_meter_kwh' => self::BASE_RUNTIME_HOURS + $totalEnergy,
            'reading_count' => count($eventRows),
            'intervention_count' => count($interventionRows),
            'total_technical_impact' => $totalEnergy,
            'current_start' => $slot['start'],
            'current_end' => $slot['end'],
            'next_sequence' => (int) $slot['sequence'],
            'next_source_reference' => sprintf('EVT-DEMO-%04d', (int) $slot['sequence']),
            'last_communication_at' => $latestReading['created_at'] ?? null,
            'latest_hash' => $latestIntervention['record_hash'] ?? null,
            'latest_intervention' => $latestIntervention,
            'latest_readings' => $latestReadings,
            'latest_interventions' => $latestInterventions,
        ];
    }

    private function nextSlot(int $organizationId, int $siteId, int $turbineId): array
    {
        $lastIntervention = db_connect()->table('maintenance_interventions')
            ->select('intervention_code, scheduled_end_at')
            ->where('organization_id', $organizationId)
            ->where('site_id', $siteId)
            ->where('turbine_id', $turbineId)
            ->like('intervention_code', 'MI-DEMO-', 'after')
            ->orderBy('scheduled_end_at', 'DESC')
            ->get(1)
            ->getRowArray();

        $start = $lastIntervention['scheduled_end_at'] ?? self::DEFAULT_START;
        $end = date('Y-m-d H:i:s', strtotime($start . ' +10 minutes'));
        $sequence = 1;

        if (! empty($lastIntervention['intervention_code']) && preg_match('/(\d+)$/', (string) $lastIntervention['intervention_code'], $matches)) {
            $sequence = ((int) $matches[1]) + 1;
        }

        return [
            'start' => $start,
            'end' => $end,
            'sequence' => $sequence,
        ];
    }

    private function ensureDemoAssets(): array
    {
        $organizations = new OrganizationModel();
        $sites = new SiteModel();
        $turbines = new TurbineModel();

        $organization = $organizations->where('slug', self::ORG_SLUG)->first();
        if (! $organization) {
            $organizationId = $organizations->insert([
                'name' => 'Quantum Wind Operations Demo',
                'slug' => self::ORG_SLUG,
                'organization_type' => 'operator',
                'country_code' => 'PT',
                'email' => 'ops-demo@quantum.local',
                'website' => 'https://demo.quantum.local',
                'status' => 'active',
            ], true);
            $organization = $organizations->find($organizationId);
        }

        $site = $sites->where('organization_id', (int) $organization['id'])
            ->where('site_code', self::SITE_CODE)
            ->first();

        if (! $site) {
            $siteId = $sites->insert([
                'organization_id' => (int) $organization['id'],
                'name' => 'Quantum Demo Wind Farm',
                'site_code' => self::SITE_CODE,
                'site_type' => 'wind_farm',
                'country_code' => 'PT',
                'region' => 'Lisbon',
                'location' => 'Lisboa Demo Lab',
                'commissioned_at' => '2026-03-01',
                'status' => 'active',
            ], true);
            $site = $sites->find($siteId);
        }

        $turbine = $turbines->where('site_id', (int) $site['id'])
            ->where('turbine_code', self::TURBINE_CODE)
            ->first();

        if (! $turbine) {
            $turbineId = $turbines->insert([
                'site_id' => (int) $site['id'],
                'turbine_code' => self::TURBINE_CODE,
                'name' => 'Quantum Demo Turbine',
                'manufacturer' => 'Vestas',
                'model' => 'V136-4.2MW',
                'serial_number' => 'QTM-DEMO-001',
                'rated_power_kw' => 4200.00,
                'hub_height_m' => 112.00,
                'rotor_diameter_m' => 136.00,
                'commissioned_at' => '2026-03-01',
                'status' => 'active',
            ], true);
            $turbine = $turbines->find($turbineId);
        }

        return [
            'organization' => $organization,
            'site' => $site,
            'turbine' => $turbine,
        ];
    }
}
