<?php

declare(strict_types=1);

namespace App\Business\Integration\Support;

use App\Business\Integration\DTOs\SyncContext;
use App\Business\Integration\Enums\IntegrationSyncStatus;
use App\Models\DberpIntegrationSyncLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

/**
 * 联通侧结构化日志入口（占位）：后续与 dberp_integration_sync_logs 对齐。
 */
final class IntegrationLogger
{
    public static function start(SyncContext $syncContext, ?Model $relatedModel = null, ?string $message = null, array $context = []): DberpIntegrationSyncLog
    {
        $normalizedContext = self::normalizeContext($syncContext, $context);
        $payload = [
            'channel' => $syncContext->channel,
            'direction' => $syncContext->direction,
            'status' => IntegrationSyncStatus::Pending->value,
            'sync_object_type' => $syncContext->objectType,
            'source_system' => $syncContext->sourceSystem ?? $syncContext->channel,
            'target_system' => $syncContext->targetSystem,
            'reference' => $syncContext->reference,
            'source_document_no' => self::extractSourceDocumentNo($syncContext->reference, $normalizedContext),
            'external_reference' => self::extractExternalReference($syncContext->reference, $normalizedContext),
            'message' => $message,
            'result_summary' => self::buildResultSummary(IntegrationSyncStatus::Pending, $message),
            'context' => $normalizedContext,
            'related_model_type' => $relatedModel?->getMorphClass(),
            'related_model_id' => $relatedModel?->getKey(),
        ];

        Log::channel('single')->info('[integration:start] '.$syncContext->channel.' '.($message ?? ''), $payload['context']);

        return DberpIntegrationSyncLog::query()->create($payload);
    }

    public static function success(DberpIntegrationSyncLog $log, string $message, array $context = []): void
    {
        self::finish($log, IntegrationSyncStatus::Success, $message, $context);
    }

    public static function failure(DberpIntegrationSyncLog $log, string $message, array $context = [], ?string $errorType = null): void
    {
        self::finish($log, IntegrationSyncStatus::Failed, $message, $context, $errorType);
    }

    public static function skipped(DberpIntegrationSyncLog $log, string $message, array $context = [], ?string $errorType = null): void
    {
        self::finish($log, IntegrationSyncStatus::Skipped, $message, $context, $errorType);
    }

    public static function updateRetryResult(DberpIntegrationSyncLog $log, IntegrationSyncStatus $status, string $message): void
    {
        $log->forceFill([
            'latest_retry_at' => now(),
            'latest_retry_status' => $status->value,
            'latest_retry_message' => Str::limit($message, 255, ''),
        ])->save();
    }

    public static function note(string $channel, string $message, array $context = []): void
    {
        Log::channel('single')->info('[integration] '.$channel.' '.$message, $context);
    }

    private static function finish(DberpIntegrationSyncLog $log, IntegrationSyncStatus $status, string $message, array $context, ?string $errorType = null): void
    {
        $mergedContext = array_merge($log->context ?? [], $context);

        $log->forceFill([
            'status' => $status->value,
            'message' => $message,
            'error_type' => $errorType,
            'result_summary' => self::buildResultSummary($status, $message),
            'source_document_no' => self::extractSourceDocumentNo($log->reference, $mergedContext, $log->source_document_no),
            'external_reference' => self::extractExternalReference($log->reference, $mergedContext, $log->external_reference),
            'context' => $mergedContext,
        ])->save();

        Log::channel('single')->info('[integration:finish] '.$log->channel.' '.$message, $mergedContext);
    }

    private static function normalizeContext(SyncContext $syncContext, array $context): array
    {
        return array_filter([
            'correlation_id' => $syncContext->correlationId,
            'idempotency_key' => $syncContext->idempotencyKey,
            'operator_id' => $syncContext->operatorId,
            ...$context,
        ], static fn ($value): bool => $value !== null);
    }

    private static function extractSourceDocumentNo(?string $reference, array $context, ?string $fallback = null): ?string
    {
        foreach (['source_document_no', 'order_no', 'source_transaction_number', 'external_code'] as $key) {
            $value = $context[$key] ?? null;

            if (is_scalar($value) && (string) $value !== '') {
                return (string) $value;
            }
        }

        return $fallback ?: ($reference !== '' ? $reference : null);
    }

    private static function extractExternalReference(?string $reference, array $context, ?string $fallback = null): ?string
    {
        foreach (['external_reference', 'external_order_id', 'external_product_id', 'external_member_id', 'external_id'] as $key) {
            $value = $context[$key] ?? null;

            if (is_scalar($value) && (string) $value !== '') {
                return (string) $value;
            }
        }

        return $fallback ?: (($context['idempotency_key'] ?? null) === null ? null : $reference);
    }

    private static function buildResultSummary(IntegrationSyncStatus $status, ?string $message): ?string
    {
        if ($message === null || $message === '') {
            return null;
        }

        return Str::limit($status->label().'：'.$message, 255, '');
    }
}
