<?php

namespace App\Support;

use App\Models\OrdenLavanderia;
use App\Models\TipoServicio;

/**
 * Contenido homologado de etiquetas de bolsa (térmica ESC/POS y PDF).
 */
class LaundryBagLabel
{
    /**
     * @return array{cliente: string, fecha_entrega: string, tipo_servicio: string}
     */
    public static function metaDesdeOrden(OrdenLavanderia $orden): array
    {
        $orden->loadMissing(['slaTipoServicio', 'cliente']);

        return [
            'cliente' => self::clienteParaEtiqueta($orden),
            'fecha_entrega' => self::fechaEntregaEtiqueta($orden),
            'tipo_servicio' => self::tipoServicioEtiqueta($orden),
        ];
    }

    public static function clienteParaEtiqueta(OrdenLavanderia $orden): string
    {
        $nombre = trim((string) ($orden->cliente?->nombre ?? $orden->cliente_nombre ?? 'Mostrador'));

        return mb_strtoupper(self::normalizarTexto($nombre), 'UTF-8');
    }

    public static function fechaEntregaEtiqueta(OrdenLavanderia $orden): string
    {
        return LaundrySemaphoreColorResolver::formatEntregaTicket(
            LaundrySemaphoreColorResolver::promisedAt($orden)
        );
    }

    public static function tipoServicioEtiqueta(OrdenLavanderia $orden): string
    {
        $orden->loadMissing('slaTipoServicio');
        $sla = $orden->slaTipoServicio;
        if ($sla !== null) {
            $code = strtolower((string) ($sla->code ?? ''));

            return match ($code) {
                TipoServicio::CODE_URGENT => 'URGENTE',
                TipoServicio::CODE_EXPRESS => 'EXPRESS',
                TipoServicio::CODE_NORMAL => 'NORMAL',
                default => mb_strtoupper(trim((string) $sla->name), 'UTF-8') ?: 'NORMAL',
            };
        }

        if ($orden->is_priority) {
            return 'URGENTE';
        }

        return 'NORMAL';
    }

    public static function contenidoTermico(
        OrdenLavanderia $orden,
        ?int $anchoLinea = null,
        ?int $indiceBolsa = null,
        ?int $totalBolsas = null
    ): string {
        $ancho = max(32, min(64, $anchoLinea ?? ThermalLineWidth::DEFAULT_CHARS_80MM));
        $meta = self::metaDesdeOrden($orden);
        $folioBarcode = LaundryScanResolver::barcodePayloadForOrder($orden);

        $lineas = ['@@DASH', '@@PAD:1'];
        foreach (self::lineasNombreClienteTermico($meta['cliente'], $ancho) as $nombreLinea) {
            $lineas[] = $nombreLinea;
        }
        $lineas[] = '@@CENTER:ENTREGA: '.$meta['fecha_entrega'];
        $lineas[] = '@@CENTER:SERVICIO: '.$meta['tipo_servicio'];
        if ($totalBolsas !== null && $totalBolsas > 1 && $indiceBolsa !== null) {
            $lineas[] = '@@CENTER:Bolsa '.$indiceBolsa.' de '.$totalBolsas;
        }
        $lineas[] = '@@PAD:1';
        if ($folioBarcode !== '') {
            $lineas[] = '@@BARCODE:'.$folioBarcode;
            $lineas[] = '@@CENTER:'.$folioBarcode;
        }
        $lineas[] = '@@PAD:1';
        $lineas[] = '@@DASH';
        $lineas[] = '@@LABEL_END';
        $lineas[] = '';

        return implode("\n", $lineas);
    }

    /**
     * @return list<string>
     */
    private static function lineasNombreClienteTermico(string $cliente, int $ancho): array
    {
        $cliente = trim($cliente);
        if ($cliente === '') {
            return ['@@CENTER:—'];
        }

        $maxChars = max(14, $ancho - 2);
        $partes = explode("\n", wordwrap($cliente, $maxChars, "\n", true));
        $partes = array_values(array_filter(
            array_slice($partes, 0, 2),
            static fn (string $p): bool => trim($p) !== ''
        ));

        return array_map(
            static fn (string $parte): string => '@@CENTER:'.trim($parte),
            $partes
        );
    }

    private static function normalizarTexto(string $texto): string
    {
        if ($texto === '') {
            return '';
        }

        $map = [
            'á' => 'a', 'é' => 'e', 'í' => 'i', 'ó' => 'o', 'ú' => 'u',
            'Á' => 'A', 'É' => 'E', 'Í' => 'I', 'Ó' => 'O', 'Ú' => 'U',
            'ñ' => 'n', 'Ñ' => 'N', 'ü' => 'u', 'Ü' => 'U',
        ];

        return strtr($texto, $map);
    }
}
