<?php

declare(strict_types=1);

namespace ImovelZapAi\Documents\Presentation\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ContactModel;
use ImovelZapAi\Documents\Application\Actions\AddDocumentCommentAction;
use ImovelZapAi\Documents\Application\Actions\CreateDocumentAction;
use ImovelZapAi\Documents\Application\Actions\CreateDocumentVersionAction;
use ImovelZapAi\Documents\Application\Actions\SaveDocumentTemplateAction;
use ImovelZapAi\Documents\Application\Actions\ShareDocumentAction;
use ImovelZapAi\Documents\Application\Queries\GetDocumentDashboardQuery;
use ImovelZapAi\Documents\Application\Queries\ListDocumentsQuery;
use ImovelZapAi\Documents\Application\Services\DefaultDocumentTemplateSeeder;
use ImovelZapAi\Documents\Application\Services\DocumentVariableCatalog;
use ImovelZapAi\Documents\Domain\Enums\DocumentType;
use ImovelZapAi\Documents\Domain\Exceptions\DocumentException;
use ImovelZapAi\Documents\Infrastructure\Persistence\Eloquent\BusinessDocumentModel;
use ImovelZapAi\Documents\Infrastructure\Persistence\Eloquent\DocumentTemplateModel;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyModel;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;
use ImovelZapAi\Tenancy\Support\TenantContext;

final class DocumentWebController extends Controller
{
    public function index(GetDocumentDashboardQuery $dashboard, ListDocumentsQuery $list): View
    {
        $tenantId = (string) TenantContext::id();

        return view('documents.index', [
            'dashboard' => $dashboard->execute($tenantId),
            'documents' => $list->execute($tenantId, ['per_page' => 20]),
        ]);
    }

    public function create(DefaultDocumentTemplateSeeder $seeder): View
    {
        $tenantId = (string) TenantContext::id();
        $seeder->ensureForTenant($tenantId);

        return view('documents.create', [
            'contacts' => ContactModel::query()->where('tenant_id', $tenantId)->orderBy('display_name')->limit(100)->get(),
            'deals' => DealModel::query()->where('tenant_id', $tenantId)->whereNull('closed_at')->latest()->limit(50)->get(),
            'properties' => PropertyModel::query()->where('tenant_id', $tenantId)->orderBy('title')->limit(50)->get(),
            'templates' => DocumentTemplateModel::query()->where('tenant_id', $tenantId)->orderBy('name')->get(),
            'documentTypes' => DocumentType::cases(),
        ]);
    }

    public function store(Request $request, CreateDocumentAction $action, ShareDocumentAction $share): RedirectResponse
    {
        $data = $request->validate([
            'contact_id' => ['required', 'uuid'],
            'deal_id' => ['nullable', 'uuid'],
            'property_id' => ['nullable', 'uuid'],
            'template_id' => ['nullable', 'uuid'],
            'document_type' => ['nullable', 'string'],
            'amount' => ['nullable', 'numeric'],
            'intro_message' => ['nullable', 'string'],
            'share_now' => ['nullable', 'boolean'],
        ]);

        try {
            $document = $action->execute((string) TenantContext::id(), $request->user(), $data);
        } catch (DocumentException $e) {
            return back()->withInput()->with('error', $e->getMessage());
        }

        $status = 'Documento criado.';
        $url = null;
        if ($request->boolean('share_now')) {
            try {
                $result = $share->execute($document, $request->user(), true);
                $url = $result['url'];
                $status = 'Documento criado e link enviado.';
            } catch (\Throwable $e) {
                $status = 'Documento criado. Envio: '.$e->getMessage();
                try {
                    $result = $share->execute($document, $request->user(), false);
                    $url = $result['url'];
                } catch (\Throwable) {
                }
            }
        }

        return redirect()->route('documents.show', $document)
            ->with('status', $status)
            ->with('document_url', $url);
    }

    public function show(string $document): View
    {
        $model = BusinessDocumentModel::query()
            ->where('tenant_id', TenantContext::id())
            ->whereKey($document)
            ->with(['contact', 'property', 'deal', 'currentVersion', 'versions', 'histories', 'comments', 'views'])
            ->firstOrFail();

        return view('documents.show', ['document' => $model]);
    }

    public function share(string $document, Request $request, ShareDocumentAction $action): RedirectResponse
    {
        try {
            $result = $action->execute($this->find($document), $request->user(), true);
        } catch (\Throwable $e) {
            return back()->with('error', $e->getMessage());
        }

        return back()->with('status', 'Link enviado.')->with('document_url', $result['url']);
    }

    public function version(string $document, Request $request, CreateDocumentVersionAction $action): RedirectResponse
    {
        $data = $request->validate([
            'amount' => ['nullable', 'numeric'],
            'intro_message' => ['nullable', 'string'],
            'change_summary' => ['nullable', 'string'],
        ]);

        try {
            $action->execute($this->find($document), $request->user(), $data);
        } catch (DocumentException $e) {
            return back()->with('error', $e->getMessage());
        }

        return back()->with('status', 'Nova versão criada.');
    }

    public function comment(string $document, Request $request, AddDocumentCommentAction $action): RedirectResponse
    {
        $data = $request->validate(['body' => ['required', 'string']]);
        $action->execute($this->find($document), $data['body'], 'broker', $request->user());

        return back()->with('status', 'Comentário registrado.');
    }

    public function templates(DefaultDocumentTemplateSeeder $seeder): View
    {
        $tenantId = (string) TenantContext::id();
        $seeder->ensureForTenant($tenantId);

        return view('documents.templates.index', [
            'templates' => DocumentTemplateModel::query()->where('tenant_id', $tenantId)->orderBy('name')->get(),
        ]);
    }

    public function templateCreate(DocumentVariableCatalog $catalog): View
    {
        return view('documents.templates.form', [
            'template' => null,
            'variables' => $catalog->all(),
            'documentTypes' => DocumentType::cases(),
        ]);
    }

    public function templateStore(Request $request, SaveDocumentTemplateAction $action): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string'],
            'document_type' => ['required', 'string'],
            'body_html' => ['required', 'string'],
            'is_default' => ['nullable', 'boolean'],
        ]);

        $action->execute((string) TenantContext::id(), $request->user(), $data);

        return redirect()->route('documents.templates.index')->with('status', 'Template salvo.');
    }

    public function templateEdit(string $template, DocumentVariableCatalog $catalog): View
    {
        $model = $this->findTemplate($template);

        return view('documents.templates.form', [
            'template' => $model,
            'variables' => $catalog->all(),
            'documentTypes' => DocumentType::cases(),
        ]);
    }

    public function templateUpdate(string $template, Request $request, SaveDocumentTemplateAction $action): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string'],
            'document_type' => ['required', 'string'],
            'body_html' => ['required', 'string'],
            'is_default' => ['nullable', 'boolean'],
        ]);

        $action->execute((string) TenantContext::id(), $request->user(), $data, $this->findTemplate($template));

        return redirect()->route('documents.templates.index')->with('status', 'Template atualizado.');
    }

    private function find(string $id): BusinessDocumentModel
    {
        return BusinessDocumentModel::query()->where('tenant_id', TenantContext::id())->whereKey($id)->firstOrFail();
    }

    private function findTemplate(string $id): DocumentTemplateModel
    {
        return DocumentTemplateModel::query()->where('tenant_id', TenantContext::id())->whereKey($id)->firstOrFail();
    }
}
