<?php

declare(strict_types=1);

namespace ImovelZapAi\Conversations\Infrastructure\Http\Controllers\Web;

use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use ImovelZapAi\Conversations\Application\Actions\ClaimHandoffAction;
use ImovelZapAi\Conversations\Application\Actions\EnsureConversationSummaryAction;
use ImovelZapAi\Conversations\Application\Actions\SendBrokerReplyAction;
use ImovelZapAi\Conversations\Application\Actions\SuggestBrokerReplyAction;
use ImovelZapAi\Conversations\Application\Actions\UpdatePersonInterestStageAction;
use ImovelZapAi\Conversations\Application\Actions\CreateBrokerNoteAction;
use ImovelZapAi\Conversations\Application\Actions\DeleteBrokerNoteAction;
use ImovelZapAi\Conversations\Application\Queries\BrokerNotesQuery;
use ImovelZapAi\Conversations\Application\Queries\ConversationPropertiesQuery;
use ImovelZapAi\Conversations\Application\Queries\PeopleFunnelQuery;
use ImovelZapAi\Conversations\Application\Queries\PersonTimelineQuery;
use ImovelZapAi\Conversations\Application\Queries\SmartInboxQuery;
use ImovelZapAi\Conversations\Application\Services\ConversationSummaryPresenter;
use ImovelZapAi\Conversations\Domain\Enums\InboxSection;
use ImovelZapAi\Conversations\Domain\Enums\PeopleFunnelStage;
use ImovelZapAi\Conversations\Application\Queries\ConversationThreadQuery;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\BrokerNoteModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ContactModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ConversationModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\HumanHandoffModel;
use ImovelZapAi\Properties\Domain\Enums\PropertyInterestStatus;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyInterestModel;
use ImovelZapAi\Conversations\Application\Services\WhatsAppLinkBuilder;
use ImovelZapAi\Tenancy\Support\TenantContext;
use InvalidArgumentException;

final class PeopleController
{
    public function index(Request $request, PeopleFunnelQuery $query): View
    {
        $requested = $request->query('estagio');
        $stage = is_string($requested) && $requested !== ''
            ? PeopleFunnelStage::fromQuery($requested)
            : $query->defaultStage();

        return view('conversations.people.index', [
            'stage' => $stage,
            'stages' => PeopleFunnelStage::ordered(),
            'counts' => $query->counts(),
            'items' => $query->items($stage),
        ]);
    }

    public function inbox(SmartInboxQuery $query): View
    {
        return view('conversations.people.inbox', [
            'sections' => InboxSection::ordered(),
            'grouped' => $query->groupedBySection(),
            'counts' => $query->counts(),
        ]);
    }

    public function show(
        string $contactId,
        Request $request,
        PersonTimelineQuery $timelineQuery,
        ConversationThreadQuery $threadQuery,
        ConversationPropertiesQuery $propertiesQuery,
        BrokerNotesQuery $notesQuery,
        EnsureConversationSummaryAction $ensureSummary,
        ConversationSummaryPresenter $summaryPresenter,
        SendBrokerReplyAction $brokerReply,
        WhatsAppLinkBuilder $whatsAppLink,
    ): View {
        $tenantId = (string) TenantContext::id();
        $contact = ContactModel::query()->whereKey($contactId)->firstOrFail();

        $conversationId = $request->query('conversa');
        $conversationId = is_string($conversationId) && $conversationId !== '' ? $conversationId : null;

        $detail = $timelineQuery->forContact($tenantId, $contactId, $conversationId);

        $summary = null;
        $thread = collect();
        $canReply = false;
        $relatedProperties = collect();
        $brokerNotes = $notesQuery->forContact($tenantId, $contactId, $conversationId);

        if ($detail->conversation !== null) {
            $summaryModel = $ensureSummary->execute($tenantId, $detail->contact, $detail->conversation);

            if ($summaryModel !== null) {
                $summary = $summaryPresenter->fromModel($summaryModel);
            }

            $thread = $threadQuery->forConversation($detail->conversation);
            $canReply = $brokerReply->canReply($detail->conversation);
            $relatedProperties = $propertiesQuery->forConversation(
                $tenantId,
                $contactId,
                $detail->conversation,
            );
        }

        return view('conversations.people.show', [
            'detail' => $detail,
            'contact' => $contact,
            'conversationId' => $conversationId,
            'summary' => $summary,
            'thread' => $thread,
            'canReply' => $canReply,
            'relatedProperties' => $relatedProperties,
            'brokerNotes' => $brokerNotes,
            'whatsAppUrl' => $whatsAppLink->forContact($contact),
        ]);
    }

    public function reply(
        string $contactId,
        Request $request,
        SendBrokerReplyAction $action,
    ): RedirectResponse {
        $validated = $request->validate([
            'conversation_id' => ['required', 'uuid'],
            'body' => ['required', 'string', 'max:4000'],
            'suggestion_id' => ['nullable', 'uuid'],
        ]);

        $tenantId = (string) TenantContext::id();
        $user = auth()->user();

        if ($user === null) {
            abort(403);
        }

        $conversation = ConversationModel::query()
            ->where('tenant_id', $tenantId)
            ->where('contact_id', $contactId)
            ->whereKey($validated['conversation_id'])
            ->firstOrFail();

        try {
            $action->execute(
                $tenantId,
                $conversation,
                $user,
                $validated['body'],
                $validated['suggestion_id'] ?? null,
            );
        } catch (InvalidArgumentException $exception) {
            return redirect()
                ->route('people.show', [
                    'contact' => $contactId,
                    'conversa' => $conversation->id,
                ])
                ->with('error', $exception->getMessage());
        }

        return redirect()
            ->route('people.show', [
                'contact' => $contactId,
                'conversa' => $conversation->id,
            ])
            ->with('success', 'Mensagem enviada pelo WhatsApp.');
    }

    public function suggestReply(
        string $contactId,
        Request $request,
        SuggestBrokerReplyAction $action,
    ): JsonResponse {
        $validated = $request->validate([
            'conversation_id' => ['required', 'uuid'],
        ]);

        $tenantId = (string) TenantContext::id();
        $user = auth()->user();

        if ($user === null) {
            abort(403);
        }

        $conversation = ConversationModel::query()
            ->where('tenant_id', $tenantId)
            ->where('contact_id', $contactId)
            ->whereKey($validated['conversation_id'])
            ->firstOrFail();

        $contact = ContactModel::query()->whereKey($contactId)->firstOrFail();

        try {
            $result = $action->execute($tenantId, $contact, $conversation, $user);
        } catch (InvalidArgumentException $exception) {
            return response()->json(['message' => $exception->getMessage()], 422);
        }

        return response()->json([
            'suggestion_id' => $result->suggestionId,
            'suggestion' => $result->suggestion,
            'generated_by' => $result->generatedBy,
        ]);
    }

    public function storeNote(
        string $contactId,
        Request $request,
        CreateBrokerNoteAction $action,
    ): RedirectResponse {
        $validated = $request->validate([
            'note_body' => ['required', 'string', 'max:2000'],
            'conversation_id' => ['nullable', 'uuid'],
            'property_id' => ['nullable', 'uuid'],
        ]);

        $tenantId = (string) TenantContext::id();
        $user = auth()->user();

        if ($user === null) {
            abort(403);
        }

        $contact = ContactModel::query()->whereKey($contactId)->firstOrFail();

        try {
            $action->execute(
                $tenantId,
                $contact,
                $user,
                $validated['note_body'],
                $validated['conversation_id'] ?? null,
                $validated['property_id'] ?? null,
            );
        } catch (InvalidArgumentException $exception) {
            return redirect()
                ->route('people.show', [
                    'contact' => $contactId,
                    'conversa' => $validated['conversation_id'] ?? null,
                ])
                ->with('error', $exception->getMessage());
        }

        return redirect()
            ->route('people.show', [
                'contact' => $contactId,
                'conversa' => $validated['conversation_id'] ?? null,
            ])
            ->with('success', 'Nota privada salva. O cliente não verá este conteúdo.')
            ->withFragment('notas-privadas');
    }

    public function destroyNote(
        string $contactId,
        string $noteId,
        Request $request,
        DeleteBrokerNoteAction $action,
    ): RedirectResponse {
        $tenantId = (string) TenantContext::id();
        $note = BrokerNoteModel::query()
            ->where('tenant_id', $tenantId)
            ->where('contact_id', $contactId)
            ->whereKey($noteId)
            ->firstOrFail();

        $conversationId = $request->query('conversa');

        try {
            $action->execute($tenantId, $note);
        } catch (InvalidArgumentException $exception) {
            return redirect()
                ->route('people.show', [
                    'contact' => $contactId,
                    'conversa' => is_string($conversationId) ? $conversationId : null,
                ])
                ->with('error', $exception->getMessage());
        }

        return redirect()
            ->route('people.show', [
                'contact' => $contactId,
                'conversa' => is_string($conversationId) ? $conversationId : null,
            ])
            ->with('success', 'Nota removida.');
    }

    public function claim(string $handoffId, ClaimHandoffAction $action): RedirectResponse
    {
        $tenantId = (string) TenantContext::id();
        $handoff = HumanHandoffModel::query()->whereKey($handoffId)->firstOrFail();
        $user = auth()->user();

        if ($user !== null) {
            $action->execute($tenantId, $handoff, $user);
        }

        return redirect()
            ->route('people.index', ['estagio' => PeopleFunnelStage::Negotiating->value])
            ->with('success', 'Atendimento assumido. A pessoa está em negociação.');
    }

    public function closeInterest(
        string $interestId,
        Request $request,
        UpdatePersonInterestStageAction $action,
    ): RedirectResponse {
        $validated = $request->validate([
            'status' => ['required', 'in:closed_won,closed_rental,lost'],
        ]);

        $tenantId = (string) TenantContext::id();
        $interest = PropertyInterestModel::query()->whereKey($interestId)->firstOrFail();
        $status = PropertyInterestStatus::from($validated['status']);

        $action->execute($tenantId, $interest, $status);

        $message = match ($status) {
            PropertyInterestStatus::ClosedWon => 'Venda registrada como fechada.',
            PropertyInterestStatus::ClosedRental => 'Aluguel registrado como concluído.',
            PropertyInterestStatus::Lost => 'Atendimento registrado como desistência.',
        };

        return redirect()
            ->route('people.index', ['estagio' => PeopleFunnelStage::Closed->value])
            ->with('success', $message);
    }
}
