<?php

namespace App\Controllers\Api;

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

class Maintenance extends BaseApiController
{
    public function preview()
    {
        if ($response = $this->requireAnyApiScope(['maintenance:write', 'certificates:write'])) {
            return $response;
        }

        $payload = $this->payload();
        $data = $this->buildData($payload);
        $data['intervention_code'] = $data['intervention_code'] ?: $this->nextInterventionCode();

        if ($validation = $this->validatePayload($data, false)) {
            return $validation;
        }

        $site = (new SiteModel())->find((int) $data['site_id']);
        $turbine = $data['turbine_id'] ? (new TurbineModel())->find((int) $data['turbine_id']) : null;

        return $this->respondOk([
            'intervention_code' => $data['intervention_code'],
            'organization_id' => $data['organization_id'],
            'site' => [
                'id' => $site['id'],
                'name' => $site['name'],
                'site_code' => $site['site_code'],
            ],
            'turbine' => $turbine ? [
                'id' => $turbine['id'],
                'turbine_code' => $turbine['turbine_code'],
                'name' => $turbine['name'],
            ] : null,
            'title' => $data['title'],
            'intervention_type' => $data['intervention_type'],
            'maintenance_mode' => $data['maintenance_mode'],
            'priority' => $data['priority'],
            'status' => $data['status'],
            'external_reference' => $data['external_reference'],
            'warnings' => $turbine ? [] : ['This intervention is not linked to a turbine.'],
        ]);
    }

    public function index()
    {
        if ($response = $this->requireAnyApiScope(['maintenance:read', 'certificates:read'])) {
            return $response;
        }

        $builder = (new MaintenanceInterventionModel())
            ->withRelations()
            ->where('maintenance_interventions.organization_id', $this->apiOrganizationId());

        $status = trim((string) $this->request->getGet('status'));
        if ($status !== '') {
            $builder->where('maintenance_interventions.status', $status);
        }

        $siteId = (int) ($this->request->getGet('site_id') ?? 0);
        if ($siteId > 0) {
            $builder->where('maintenance_interventions.site_id', $siteId);
        }

        $turbineId = (int) ($this->request->getGet('turbine_id') ?? 0);
        if ($turbineId > 0) {
            $builder->where('maintenance_interventions.turbine_id', $turbineId);
        }

        return $this->respondOk(
            $builder->orderBy('maintenance_interventions.created_at', 'DESC')->findAll(100)
        );
    }

    public function show(string $code)
    {
        if ($response = $this->requireAnyApiScope(['maintenance:read', 'certificates:read'])) {
            return $response;
        }

        $intervention = (new MaintenanceInterventionModel())
            ->withRelations()
            ->where('maintenance_interventions.organization_id', $this->apiOrganizationId())
            ->where('maintenance_interventions.intervention_code', $code)
            ->first();

        if (! $intervention) {
            return $this->failNotFound('Maintenance intervention not found.');
        }

        return $this->respondOk([
            'intervention' => $intervention,
            'events' => (new MaintenanceEventModel())
                ->where('maintenance_intervention_id', $intervention['id'])
                ->orderBy('happened_at', 'DESC')
                ->findAll(),
            'files' => (new MaintenanceFileModel())
                ->where('maintenance_intervention_id', $intervention['id'])
                ->orderBy('created_at', 'DESC')
                ->findAll(),
            'transactions' => (new BlockchainTransactionModel())
                ->where('maintenance_intervention_id', $intervention['id'])
                ->orderBy('created_at', 'DESC')
                ->findAll(),
        ]);
    }

    public function create()
    {
        if ($response = $this->requireAnyApiScope(['maintenance:write', 'certificates:write'])) {
            return $response;
        }

        $data = $this->buildData($this->payload());
        $data['intervention_code'] = $data['intervention_code'] ?: $this->nextInterventionCode();

        if ($validation = $this->validatePayload($data, true)) {
            return $validation;
        }

        $model = new MaintenanceInterventionModel();
        $id = $model->insert($data, true);

        return $this->respondOk($model->find($id), 201);
    }

    private function buildData(array $payload): array
    {
        return [
            'organization_id' => $this->apiOrganizationId(),
            'site_id' => (int) ($payload['site_id'] ?? 0),
            'turbine_id' => $this->nullableInt($payload['turbine_id'] ?? null),
            'intervention_code' => trim((string) ($payload['intervention_code'] ?? '')),
            'title' => trim((string) ($payload['title'] ?? '')),
            'description' => trim((string) ($payload['description'] ?? '')) ?: null,
            'intervention_type' => trim((string) ($payload['intervention_type'] ?? 'preventive')) ?: 'preventive',
            'maintenance_mode' => trim((string) ($payload['maintenance_mode'] ?? 'scheduled')) ?: 'scheduled',
            'priority' => trim((string) ($payload['priority'] ?? 'medium')) ?: 'medium',
            'status' => trim((string) ($payload['status'] ?? 'planned')) ?: 'planned',
            'reported_at' => trim((string) ($payload['reported_at'] ?? '')) ?: null,
            'scheduled_start_at' => trim((string) ($payload['scheduled_start_at'] ?? '')) ?: null,
            'scheduled_end_at' => trim((string) ($payload['scheduled_end_at'] ?? '')) ?: null,
            'started_at' => trim((string) ($payload['started_at'] ?? '')) ?: null,
            'completed_at' => trim((string) ($payload['completed_at'] ?? '')) ?: null,
            'created_by_user_id' => null,
            'assigned_to_user_id' => $this->nullableInt($payload['assigned_to_user_id'] ?? null),
            'external_reference' => trim((string) ($payload['external_reference'] ?? '')) ?: null,
        ];
    }

    private function validatePayload(array $data, bool $requireUniqueCode)
    {
        $rules = [
            'organization_id' => 'required|integer',
            'site_id' => 'required|integer',
            'turbine_id' => 'permit_empty|integer',
            'intervention_code' => 'required|max_length[120]',
            'title' => 'required|min_length[3]|max_length[160]',
            'description' => 'permit_empty',
            'intervention_type' => 'required|in_list[preventive,corrective,inspection,audit,emergency]',
            'maintenance_mode' => 'required|in_list[scheduled,corrective,condition_based,outage]',
            'priority' => 'required|in_list[low,medium,high,critical]',
            'status' => 'required|in_list[planned,in_progress,completed,cancelled,on_hold]',
            'reported_at' => 'permit_empty',
            'scheduled_start_at' => 'permit_empty',
            'scheduled_end_at' => 'permit_empty',
            'started_at' => 'permit_empty',
            'completed_at' => 'permit_empty',
            'assigned_to_user_id' => 'permit_empty|integer',
            'external_reference' => 'permit_empty|max_length[120]',
        ];

        if (! $this->validateData($data, $rules)) {
            return $this->failValidation($this->validator->getErrors());
        }

        $site = (new SiteModel())->find((int) $data['site_id']);
        if (! $site || (int) $site['organization_id'] !== $this->apiOrganizationId()) {
            return $this->failForbidden('The selected site does not belong to this API key tenant.');
        }

        if ($data['turbine_id'] !== null) {
            $turbine = (new TurbineModel())->find((int) $data['turbine_id']);
            if (! $turbine || (int) $turbine['site_id'] !== (int) $data['site_id']) {
                return $this->failValidation([
                    'turbine_id' => 'The selected turbine does not belong to the chosen site.',
                ]);
            }
        }

        if ($requireUniqueCode) {
            $exists = (new MaintenanceInterventionModel())
                ->where('organization_id', $data['organization_id'])
                ->where('intervention_code', $data['intervention_code'])
                ->first();

            if ($exists) {
                return $this->failValidation([
                    'intervention_code' => 'A maintenance intervention with this code already exists.',
                ]);
            }
        }

        return null;
    }

    private function nextInterventionCode(): string
    {
        $prefix = 'MI-' . date('Y') . '-';

        $last = (new MaintenanceInterventionModel())
            ->select('intervention_code')
            ->where('organization_id', $this->apiOrganizationId())
            ->like('intervention_code', $prefix, 'after')
            ->orderBy('id', 'DESC')
            ->first();

        if (! $last || empty($last['intervention_code'])) {
            return $prefix . '0001';
        }

        $lastNumber = (int) substr((string) $last['intervention_code'], -4);

        return $prefix . str_pad((string) ($lastNumber + 1), 4, '0', STR_PAD_LEFT);
    }

    private function nullableInt($value): ?int
    {
        $value = trim((string) $value);

        return $value === '' ? null : (int) $value;
    }
}
