<?php

namespace MintyPHP\Module\Helpdesk\Service;

use MintyPHP\Module\Helpdesk\Repository\HandoverRepository;
use MintyPHP\Module\Helpdesk\Repository\UpdateRepository;

/**
 * Service for loading domain detail data (master data, customer, contract, handovers).
 *
 * Provides loadDomain() for the synchronous page load and loadDomainDetails()
 * for the async data endpoint.
 */
class DomainDetailService
{
    public function __construct(
        private readonly BcODataGateway $bcODataGateway,
        private readonly EffectiveHelpdeskSettingsService $settingsGateway,
        private readonly HandoverRepository $handoverRepository,
        private readonly ?UpdateRepository $updateRepository = null
    ) {
    }

    /**
     * Load domain master data (1 OData call).
     *
     * Used by the main page load — customer, contract, handovers loaded async.
     *
     * @api Called from domain($id) action
     * @return array{status: string, domain?: array<string, mixed>, error?: string}
     */
    public function loadDomain(string $domainNo): array
    {
        $domainNo = trim($domainNo);
        if ($domainNo === '') {
            return ['status' => 'not_found'];
        }

        if (!$this->settingsGateway->isConfigured()) {
            return ['status' => 'not_configured', 'error' => 'BC connection not configured'];
        }

        try {
            $domain = $this->bcODataGateway->getDomain($domainNo);
        } catch (\Throwable) {
            return ['status' => 'error', 'error' => 'BC connection failed'];
        }

        if ($domain === null) {
            return ['status' => 'not_found'];
        }

        return [
            'status' => 'success',
            'domain' => $domain,
        ];
    }

    /**
     * Load all detail data for a domain (for async data endpoint).
     *
     * @api Called from domain-detail-data endpoint
     * @return array{
     *   ok: bool,
     *   customer?: array<string, mixed>|null,
     *   contract?: array<string, mixed>|null,
     *   handovers?: list<array<string, mixed>>,
     *   handover_stats?: array{total: int, draft: int, in_progress: int, completed: int, archived: int},
     *   related_domains?: list<array<string, mixed>>,
     *   error?: string
     * }
     */
    public function loadDomainDetails(string $domainNo, string $customerNo, int $tenantId): array
    {
        $domainNo = trim($domainNo);
        $customerNo = trim($customerNo);

        if ($domainNo === '') {
            return ['ok' => false, 'error' => 'Missing domain number'];
        }

        $customer = null;
        if ($customerNo !== '') {
            try {
                $customer = $this->bcODataGateway->getCustomer($customerNo);
            } catch (\Throwable) {
                // Best-effort — continue without customer data
            }
        }

        $contract = $this->loadContractForDomain($domainNo);

        $handovers = $this->handoverRepository->findByDomainNo($tenantId, $domainNo);
        $handoverStats = $this->aggregateHandoverStats($handovers);

        $relatedDomains = [];
        if ($customerNo !== '') {
            try {
                $allCustomerDomains = $this->bcODataGateway->getDomainsForCustomer($customerNo);
                $relatedDomains = array_values(array_filter(
                    $allCustomerDomains,
                    static fn (array $d): bool => trim((string) ($d['No'] ?? '')) !== $domainNo
                ));
            } catch (\Throwable) {
                // Best-effort — continue without related domains
            }
        }

        $updates = [];
        if ($this->updateRepository !== null) {
            $updates = $this->prepareUpdatesForResponse(
                $this->updateRepository->findByDomainNo($tenantId, $domainNo)
            );
        }

        return [
            'ok' => true,
            'customer' => $customer,
            'contract' => $contract,
            'handovers' => $this->prepareHandoversForResponse($handovers),
            'handover_stats' => $handoverStats,
            'updates' => $updates,
            'related_domains' => $relatedDomains,
        ];
    }

    /**
     * Load contract line info for a specific domain from BC.
     *
     * @return array<string, mixed>|null
     */
    private function loadContractForDomain(string $domainNo): ?array
    {
        try {
            $contractLines = $this->bcODataGateway->listDomainContractLines();
        } catch (\Throwable) {
            return null;
        }

        foreach ($contractLines as $line) {
            $lineNo = trim((string) ($line['No'] ?? ''));
            if ($lineNo === $domainNo) {
                return [
                    'contract_type' => trim((string) ($line['PI_Header_Type'] ?? '')),
                    'contract_no' => trim((string) ($line['Header_No'] ?? '')),
                    'contract_description' => trim((string) ($line['PI_Header_Description'] ?? '')),
                    'header_state' => trim((string) ($line['PI_Header_State'] ?? '')),
                    'line_state' => trim((string) ($line['Line_State'] ?? '')),
                ];
            }
        }

        return null;
    }

    /**
     * @param list<array<string, mixed>> $handovers
     * @return array{total: int, draft: int, in_progress: int, completed: int, archived: int}
     */
    private function aggregateHandoverStats(array $handovers): array
    {
        $stats = ['total' => 0, 'draft' => 0, 'in_progress' => 0, 'completed' => 0, 'archived' => 0];

        foreach ($handovers as $handover) {
            $stats['total']++;
            $status = trim((string) ($handover['status'] ?? ''));
            if (isset($stats[$status])) {
                $stats[$status]++;
            }
        }

        return $stats;
    }

    /**
     * Prepare update rows for the JSON response.
     *
     * @param list<array<string, mixed>> $updates
     * @return list<array<string, mixed>>
     */
    private function prepareUpdatesForResponse(array $updates): array
    {
        $prepared = [];
        foreach ($updates as $update) {
            $categoryCode = (string) ($update['category_code'] ?? '');
            $status = (string) ($update['status'] ?? '');
            $prepared[] = [
                'ticket_no' => (string) ($update['ticket_no'] ?? ''),
                'category_code' => $categoryCode,
                'category_label' => UpdateService::categoryLabel($categoryCode),
                'category_variant' => UpdateService::categoryVariant($categoryCode),
                'gitea_path' => (string) ($update['gitea_path'] ?? ''),
                'status' => $status,
                'status_label' => UpdateService::statusLabel($status),
                'status_variant' => UpdateService::statusVariant($status),
                'created_at' => (string) ($update['created_at'] ?? ''),
            ];
        }

        return $prepared;
    }

    /**
     * Prepare handover rows for the JSON response (strip internal fields).
     *
     * @param list<array<string, mixed>> $handovers
     * @return list<array<string, mixed>>
     */
    private function prepareHandoversForResponse(array $handovers): array
    {
        $prepared = [];
        foreach ($handovers as $handover) {
            $prepared[] = [
                'id' => (int) ($handover['id'] ?? 0),
                'product_code' => (string) ($handover['product_code'] ?? ''),
                'product_name' => (string) ($handover['product_name'] ?? ''),
                'product_bc_description' => (string) ($handover['product_bc_description'] ?? ''),
                'status' => (string) ($handover['status'] ?? ''),
                'created_by_name' => (string) ($handover['created_by_name'] ?? ''),
                'created_at' => (string) ($handover['created_at'] ?? ''),
            ];
        }

        return $prepared;
    }
}
