<?php

declare(strict_types=1);

namespace App\Support\AuditLogDisplay;

use BackedEnum;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Illuminate\Support\Str;
use UnitEnum;

/**
 * 将审计快照中的原始值格式化为业务可读文案（状态、布尔、空值、枚举等）。
 */
final class DberpAuditLogValueFormatter
{
    /**
     * 字段名固定映射到 dberp.options.* 的选项表（与业务对象类型无关）。
     *
     * @var array<string, string>
     */
    private const FIELD_OPTION_KEYS = [
        'settlement_method' => 'settlement_method',
        'settlement_side' => 'settlement_side',
        'settlement_business_side' => 'settlement_business_side',
        'credit_check_result' => 'credit_check_result',
        'exception_type' => 'purchase_exception_type',
        'purchase_exception_type' => 'purchase_exception_type',
        'rule_type' => 'customer_price_rule_type',
        'flow_type' => 'advance_account_flow_type',
        'batch_status' => 'inventory_batch_status',
        'serial_number_status' => 'inventory_serial_number_status',
        'expiry_status' => 'inventory_expiry_status',
        'replenishment_suggestion_status' => 'inventory_replenishment_suggestion_status',
        'difference_status' => 'stocktake_difference_status',
        'exception_status' => 'inventory_exception_status',
        'integration_mapping_status' => 'integration_mapping_status',
        'sync_status' => 'integration_sync_status',
        'execution_status' => 'purchase_order_item_execution_status',
        'document_status' => 'common_document_status',
        'record_status' => 'settlement_record_status',
        'write_off_status' => 'settlement_write_off_status',
        'line_status' => 'settlement_write_off_line_status',
        'usage_status' => 'settlement_funds_usage_status',
        'data_import_batch_status' => 'data_import_batch_status',
        'data_import_row_status' => 'data_import_row_status',
        'import_type' => 'data_import_type',
        'inquiry_quote_status' => 'purchase_inquiry_quote_status',
        'warehouse_type' => 'warehouse_type',
        'region_level' => 'region_level',
        'region_source' => 'region_source',
    ];

    /**
     * status 字段按业务对象类型映射到选项表；未列出的类型会尝试按命名约定自动匹配。
     *
     * @var array<string, string>
     */
    private const STATUS_OPTION_BY_MODEL = [
        'DberpPurchaseOrder' => 'purchase_order_status',
        'DberpSalesOrder' => 'sales_order_status',
        'DberpSalesQuote' => 'sales_quote_status',
        'DberpCustomerCategory' => 'master_record_status',
        'DberpSupplierCategory' => 'master_record_status',
        'DberpPurchaseRequest' => 'purchase_request_status',
        'DberpPurchaseReceiptOrder' => 'inventory_doc_status',
        'DberpPurchaseReturnOrder' => 'inventory_doc_status',
        'DberpSalesOutboundOrder' => 'inventory_doc_status',
        'DberpSalesReturnOrder' => 'inventory_doc_status',
        'DberpOtherStockInOrder' => 'inventory_doc_status',
        'DberpOtherStockOutOrder' => 'inventory_doc_status',
        'DberpStocktakeOrder' => 'inventory_doc_status',
        'DberpTransferOrder' => 'transfer_doc_status',
        'DberpSettlementStatement' => 'settlement_statement_status',
        'DberpSettlementAdjustment' => 'settlement_adjustment_status',
        'DberpSettlementWriteOff' => 'settlement_write_off_status',
        'DberpPaymentOrder' => 'settlement_document_status',
        'DberpReceiptOrder' => 'settlement_document_status',
        'DberpReceivableRecord' => 'receivable_status',
        'DberpPayableRecord' => 'payable_status',
        'DberpPurchaseException' => 'purchase_exception_status',
        'DberpInventoryReplenishmentSuggestion' => 'inventory_replenishment_suggestion_status',
        'DberpCustomerPriceRule' => 'customer_price_rule_status',
        'DberpInventoryBatch' => 'inventory_batch_status',
        'DberpInventorySerialNumber' => 'inventory_serial_number_status',
        'DberpAdvanceAccount' => 'advance_account_status',
    ];

    public function format(
        string $fieldKey,
        mixed $value,
        ?string $auditableType,
        DberpAuditLogRelationLabelResolver $relations,
    ): string {
        if ($value === null || $value === '') {
            return (string) __('dberp.audit_display.value_empty');
        }

        if (is_bool($value)) {
            return $value ? (string) __('dberp.audit_display.boolean_yes') : (string) __('dberp.audit_display.boolean_no');
        }

        if ($value instanceof BackedEnum) {
            return $this->format($fieldKey, $value->value, $auditableType, $relations);
        }

        if ($value instanceof UnitEnum) {
            return $this->format($fieldKey, $value->name, $auditableType, $relations);
        }

        if (is_array($value)) {
            if ($value === []) {
                return (string) __('dberp.audit_display.value_empty');
            }

            return (string) __('dberp.audit_display.complex_value_placeholder');
        }

        if (is_int($value) || is_float($value)) {
            if ($this->isBooleanishNumericField($fieldKey) && ($value === 0 || $value === 1)) {
                return $value === 1
                    ? (string) __('dberp.audit_display.boolean_yes')
                    : (string) __('dberp.audit_display.boolean_no');
            }
        }

        if ($relations->canResolveForeignKey($fieldKey)) {
            return $relations->labelForForeignKey($fieldKey, $value);
        }

        if (is_string($value) || is_int($value) || is_float($value)) {
            $stringValue = is_string($value) ? $value : (string) $value;

            $snapshotMapped = $this->mapThroughSnapshotValueLang($fieldKey, $stringValue);
            if ($snapshotMapped !== null) {
                return $snapshotMapped;
            }

            $optionMapped = $this->mapThroughOptionTables($fieldKey, $stringValue, $auditableType);
            if ($optionMapped !== null) {
                return $optionMapped;
            }

            $dateLike = $this->tryFormatDateString($stringValue);
            if ($dateLike !== null) {
                return $dateLike;
            }

            return $stringValue;
        }

        return (string) json_encode($value, JSON_UNESCAPED_UNICODE);
    }

    private function isBooleanishNumericField(string $fieldKey): bool
    {
        return match ($fieldKey) {
            'is_enabled', 'is_default', 'is_system', 'is_super_admin', 'is_delete_locked',
            'system_locked', 'spec_enabled', 'can_purchase', 'can_sale', 'manages_inventory',
            'manages_batch', 'manages_serial_number', 'manages_expiry', 'is_auxiliary_unit_enabled',
            'is_salesperson', 'warning_enabled', 'replenishment_enabled' => true,
            default => false,
        };
    }

    private function mapThroughSnapshotValueLang(string $fieldKey, string $value): ?string
    {
        $fieldSpecificKey = 'dberp.audit_display.snapshot_values.'.$fieldKey.'.'.$value;
        $fieldSpecificLabel = __($fieldSpecificKey);
        if ($fieldSpecificLabel !== $fieldSpecificKey) {
            return (string) $fieldSpecificLabel;
        }

        $commonKey = 'dberp.audit_display.snapshot_values._common.'.$value;
        $commonLabel = __($commonKey);
        if ($commonLabel !== $commonKey) {
            return (string) $commonLabel;
        }

        return null;
    }

    private function mapThroughOptionTables(string $fieldKey, string $value, ?string $auditableType): ?string
    {
        if (isset(self::FIELD_OPTION_KEYS[$fieldKey])) {
            $mapped = $this->lookupOptionsLabel(self::FIELD_OPTION_KEYS[$fieldKey], $value);
            if ($mapped !== null) {
                return $mapped;
            }
        }

        if ($fieldKey === 'status') {
            $short = $this->auditableShortClass($auditableType);
            $optionKey = $this->resolveStatusOptionKey($short);
            if ($optionKey !== null) {
                return $this->lookupOptionsLabel($optionKey, $value);
            }
        }

        return null;
    }

    private function resolveStatusOptionKey(?string $short): ?string
    {
        if ($short === null) {
            return null;
        }

        if (isset(self::STATUS_OPTION_BY_MODEL[$short])) {
            return self::STATUS_OPTION_BY_MODEL[$short];
        }

        if (! str_starts_with($short, 'Dberp')) {
            return null;
        }

        $derivedKey = Str::snake(substr($short, 5)).'_status';
        $options = __('dberp.options.'.$derivedKey);

        return is_array($options) && $options !== [] ? $derivedKey : null;
    }

    private function lookupOptionsLabel(string $optionKey, string $value): ?string
    {
        $options = __('dberp.options.'.$optionKey);

        if (! is_array($options)) {
            return null;
        }

        return $options[$value] ?? null;
    }

    private function auditableShortClass(?string $auditableType): ?string
    {
        if ($auditableType === null || $auditableType === '') {
            return null;
        }

        return class_basename($auditableType);
    }

    private function tryFormatDateString(string $value): ?string
    {
        if (strlen($value) < 8 || strlen($value) > 32) {
            return null;
        }

        try {
            $carbon = Carbon::parse($value);
        } catch (InvalidFormatException) {
            return null;
        }

        if (! $carbon->isValid()) {
            return null;
        }

        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) === 1) {
            return $carbon->toDateString();
        }

        if (preg_match('/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/', $value) === 1) {
            return $carbon->format('Y-m-d H:i');
        }

        return null;
    }
}
