<?php

declare(strict_types=1);

namespace ImovelZapAi\Conversations\Application\Services;

use Illuminate\Support\Collection;
use ImovelZapAi\Conversations\Application\Data\CatalogReplyButton;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ContactModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ConversationModel;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyModel;

final class PropertyCatalogFormatter
{
    public function searchSummary(
        Collection $properties,
        bool $purposeRelaxed = false,
        ?string $requestedPurposeLabel = null,
        bool $typeRelaxed = false,
        ?int $alternatePurposeCount = null,
        ?string $alternatePurposeLabel = null,
    ): string {
        $intro = $this->intro(
            $properties,
            $purposeRelaxed,
            $requestedPurposeLabel,
            $typeRelaxed,
            $alternatePurposeCount,
            $alternatePurposeLabel,
        );

        if ($properties->isEmpty()) {
            return $intro;
        }

        return $intro."\n\n".$this->confirmationPrompt();
    }

    public function intro(
        Collection $properties,
        bool $purposeRelaxed = false,
        ?string $requestedPurposeLabel = null,
        bool $typeRelaxed = false,
        ?int $alternatePurposeCount = null,
        ?string $alternatePurposeLabel = null,
    ): string {
        $count = $properties->count();

        if ($count === 0) {
            $base = $requestedPurposeLabel !== null
                ? "Não encontrei imóveis para *{$requestedPurposeLabel}* com esses critérios."
                : 'Não encontrei imóveis com esses critérios. Tente outro bairro, tipo ou faixa de preço.';

            if ($alternatePurposeCount !== null && $alternatePurposeCount > 0 && $alternatePurposeLabel !== null) {
                $qty = $alternatePurposeCount === 1 ? '1 imóvel' : "{$alternatePurposeCount} imóveis";

                return $base."\nHá *{$qty}* à *{$alternatePurposeLabel}* na mesma região. "
                    .'Se quiser ver esses, diga *'.mb_strtolower($alternatePurposeLabel).'* '
                    .'ou refine bairro/tipo.';
            }

            return $base;
        }

        // Compat: purposeRelaxed não deve mais acontecer no fluxo novo.
        if ($purposeRelaxed && $requestedPurposeLabel !== null) {
            if ($count === 1) {
                return "Não encontrei opções para *{$requestedPurposeLabel}*, mas achei *1 imóvel* na região.";
            }

            return "Não encontrei opções para *{$requestedPurposeLabel}*, mas achei *{$count} imóveis* na região.";
        }

        if ($typeRelaxed) {
            $purposeHint = $requestedPurposeLabel !== null ? " para *{$requestedPurposeLabel}*" : '';

            if ($count === 1) {
                return "Não encontrei esse tipo de imóvel{$purposeHint}, mas achei *1 opção*{$purposeHint} na região.";
            }

            return "Não encontrei esse tipo de imóvel{$purposeHint}, mas achei *{$count} opções*{$purposeHint} na região.";
        }

        if ($count === 1) {
            return 'Encontrei *1 imóvel* com o que você pediu.';
        }

        return "Encontrei *{$count} imóveis* com o que você pediu.";
    }

    public function confirmationPrompt(): string
    {
        return 'Quer ver esses imóveis? Responda *SIM* para continuar.';
    }

    public function awaitingConfirmationReminder(): string
    {
        return 'Responda *SIM* para ver os imóveis encontrados, ou me diga uma nova busca.';
    }

    public function browsingHelp(ConversationModel $conversation): string
    {
        return $this->actionMenu($this->hasNextProperty($conversation));
    }

    public function catalogExhaustedMessage(): string
    {
        return 'Esses foram todos os imóveis encontrados. Quer buscar em outro bairro? Me diga o que procura.';
    }

    public function propertyActionsPrompt(bool $hasNext): string
    {
        return $this->actionMenu($hasNext);
    }

    /**
     * Menu em texto — Evolution/Baileys não exibe botões interativos no celular.
     */
    public function actionMenu(bool $hasNext): string
    {
        $photos = $this->viewPhotosKeyword();
        $next = $this->showMoreKeyword();
        $visit = $this->visitKeyword();

        if ($hasNext) {
            return "O que deseja fazer?\n"
                ."Responda *{$photos}* para mais detalhes, responda *{$next}* para ver outro imóvel ou responda *{$visit}* para um corretor combinar a visita.";
        }

        return "O que deseja fazer?\n"
            ."Responda *{$photos}* para mais detalhes ou responda *{$visit}* para um corretor combinar a visita.";
    }

    public function hasNextProperty(ConversationModel $conversation): bool
    {
        /** @var list<string> $propertyIds */
        $propertyIds = $conversation->context['catalog']['property_ids'] ?? [];
        $total = count($propertyIds);

        if ($total <= 1) {
            return false;
        }

        $currentIndex = $conversation->context['catalog']['current_index'] ?? 0;

        return ((int) $currentIndex + 1) < $total;
    }

    public function propertyListingLinkMessage(PropertyModel $property, string $url): string
    {
        $title = trim((string) ($property->title ?: $property->internal_code));

        return "Confira todos os detalhes de *{$title}*:\n{$url}";
    }

    public function viewPhotosKeyword(): string
    {
        return (string) config('conversations.catalog.view_photos_keyword', 'VER FOTOS');
    }

    public function card(int $position, int $total, PropertyModel $property): string
    {
        $title = trim((string) ($property->title ?: $property->internal_code));
        $neighborhood = $property->neighborhood?->name ?? '—';
        $city = $property->city?->name ?? '—';
        $price = $this->formatPrice((float) $property->price);

        $lines = [
            "*Imóvel {$position} de {$total}*",
            "*{$title}*",
            "{$neighborhood} · {$city}",
            $property->purpose?->label() ?? '',
            $price,
        ];

        $lines = array_values(array_filter($lines, static fn (string $line): bool => trim($line) !== ''));

        $specs = [];

        if ($property->bedrooms !== null && $property->bedrooms > 0) {
            $specs[] = "{$property->bedrooms} quarto(s)";
        }

        if ($property->useful_area !== null) {
            $specs[] = (int) $property->useful_area.'m²';
        }

        if ($specs !== []) {
            $lines[] = implode(' · ', $specs);
        }

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

    public function visitButton(PropertyModel $property): CatalogReplyButton
    {
        return new CatalogReplyButton(
            id: $this->visitButtonId($property),
            label: $this->visitButtonLabel(),
        );
    }

    public function showMoreButton(): CatalogReplyButton
    {
        return new CatalogReplyButton(
            id: 'catalog:next',
            label: $this->showMoreButtonLabel(),
        );
    }

    public function visitButtonId(PropertyModel $property): string
    {
        return 'visit:'.(string) $property->id;
    }

    public function visitButtonLabel(): string
    {
        return (string) config('conversations.catalog.visit_button_label', 'Quero visitar imóvel');
    }

    public function showMoreButtonLabel(): string
    {
        return (string) config('conversations.catalog.show_more_button_label', 'Mostrar Mais');
    }

    public function visitKeyword(): string
    {
        return (string) config('conversations.catalog.visit_keyword', 'VISITAR');
    }

    public function showMoreKeyword(): string
    {
        return (string) config('conversations.catalog.show_more_keyword', 'MAIS');
    }

    public function visitButtonPrompt(): string
    {
        return (string) config(
            'conversations.catalog.visit_button_prompt',
            'Quero visitar este imóvel',
        );
    }

    public function visitInterestConfirmation(PropertyModel $property): string
    {
        $title = trim((string) ($property->title ?: $property->internal_code));

        return "Interesse registrado em *{$title}*.\nEm breve entraremos em contato sobre a visita.";
    }

    public function detail(PropertyModel $property): string
    {
        $neighborhood = $property->neighborhood?->name ?? '—';
        $city = $property->city?->name ?? '—';
        $price = $this->formatPrice((float) $property->price);
        $title = trim((string) ($property->title ?: $property->internal_code));
        $specs = [];

        if ($property->bedrooms !== null && $property->bedrooms > 0) {
            $specs[] = "{$property->bedrooms} quarto(s)";
        }

        if ($property->useful_area !== null) {
            $specs[] = (int) $property->useful_area.'m²';
        }

        $specLine = $specs !== [] ? implode(' · ', $specs) : '';

        $lines = [
            "*{$title}*",
            "{$neighborhood} · {$city}",
            trim("{$price}".($specLine !== '' ? " · {$specLine}" : '')),
        ];

        $lines[] = '';
        $lines[] = 'Quer ver outro? Responda *'.$this->showMoreKeyword().'* ou digite *outros*.';

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

    private function formatPrice(float $price): string
    {
        return 'R$ '.number_format($price, 0, ',', '.');
    }
}
