<?php

namespace App\Http\Controllers;

use App\Enums\ActorType;
use App\Enums\DeclarationStatus;
use App\Enums\MessageType;
use App\Http\Requests\StoreDeclarationMessageRequest;
use App\Mail\DeclarationConfirmationMail;
use App\Mail\DeclarationFileRequestMail;
use App\Mail\DeclarationInviteMail;
use App\Mail\DeclarationSituationMail;
use App\Mail\DeclarationTextMessageMail;
use App\Models\Declaration;
use App\Models\DeclarationInvitation;
use App\Models\Message;
use App\Models\Workspace;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class DeclarationMessageController extends Controller
{
    protected function currentWorkspace(Request $request): Workspace
    {
        $workspaceId = $request->session()->get('current_workspace_id');

        return Workspace::query()->findOrFail($workspaceId);
    }

    /**
     * Store a newly created message.
     */
    public function store(StoreDeclarationMessageRequest $request, Declaration $declaration): RedirectResponse
    {
        $workspace = $this->currentWorkspace($request);

        if ($declaration->workspace_id !== $workspace->id) {
            abort(404);
        }

        $user = $request->user();
        $type = MessageType::fromValue($request->input('type'));
        $body = $request->input('body');

        $invitation = $type->is(MessageType::Invite)
            ? $this->createInvitation($declaration)
            : $this->getOrCreateInvitation($declaration);

        $metadata = ['invitation_id' => $invitation->id];
        $message = $declaration->messages()->create([
            'type' => $type,
            'body' => $body,
            'sent_by_type' => ActorType::User,
            'sent_by_id' => $user->id,
            'metadata' => $metadata,
        ]);

        $mediaIds = [];

        if ($request->hasFile('files')) {
            foreach ($request->file('files') as $file) {
                $media = $declaration->addMedia($file)
                    ->withCustomProperties([
                        'message_id' => $message->id,
                        'uploaded_by_type' => ActorType::User,
                        'uploaded_by_id' => $user->id,
                    ])
                    ->toMediaCollection('documents');
                $mediaIds[] = $media->id;
            }
            $message->update(['metadata' => array_merge($metadata, ['media_ids' => $mediaIds])]);
        }

        $this->updateDeclarationStatusAndConfirmation($declaration, $type, $mediaIds);

        $emailSent = $this->sendEmailForMessage($declaration, $invitation, $message, $body, $type);
        $flashMessage = $emailSent
            ? 'Message envoyé.'
            : 'Message enregistré, mais l\'email du client n\'est pas configuré.';

        return back()->with('flash', ['type' => 'success', 'message' => $flashMessage]);
    }

    protected function createInvitation(Declaration $declaration): DeclarationInvitation
    {
        $declaration->load('client.primaryContact');

        return $declaration->invitations()->create([
            'email' => $declaration->client->primary_contact_email,
            'expires_at' => Carbon::now()->addDays(7),
        ]);
    }

    protected function getOrCreateInvitation(Declaration $declaration): DeclarationInvitation
    {
        $invitation = $declaration->invitations()
            ->where('expires_at', '>', now())
            ->latest()
            ->first();

        if ($invitation) {
            return $invitation;
        }

        return $this->createInvitation($declaration);
    }

    /**
     * @param  array<int>  $mediaIds
     */
    protected function updateDeclarationStatusAndConfirmation(Declaration $declaration, MessageType $type, array $mediaIds): void
    {
        // Transition through en_cours first if declaration is still in created status,
        // since created → en_attente_client is not a valid direct transition.
        if ($declaration->status->is(DeclarationStatus::Created)) {
            $declaration->update(['status' => DeclarationStatus::EnCours]);
            $declaration->refresh();
        }

        match ($type->value) {
            'invite' => $declaration->update(['status' => DeclarationStatus::EnAttenteClient]),
            'situation', 'file_request' => $declaration->update(['status' => DeclarationStatus::EnAttenteClient]),
            'confirmation' => $declaration->update([
                'status' => DeclarationStatus::EnAttenteClient,
                'confirmation_requested_at' => now(),
                'confirmation_media_id' => $mediaIds[0] ?? null,
            ]),
            default => null,
        };
    }

    protected function sendEmailForMessage(Declaration $declaration, DeclarationInvitation $invitation, Message $message, string $body, MessageType $type): bool
    {
        $declaration->load('client.primaryContact');
        $clientEmail = $declaration->client->primary_contact_email;

        if (empty($clientEmail)) {
            \Illuminate\Support\Facades\Log::warning("No primary contact email for client #{$declaration->client_id}, skipping email.");

            return false;
        }

        match ($type->value) {
            'invite' => Mail::to($clientEmail)->send(new DeclarationInviteMail($declaration, $invitation)),
            'situation' => Mail::to($clientEmail)->send(new DeclarationSituationMail($declaration, $invitation, $body)),
            'file_request' => Mail::to($clientEmail)->send(new DeclarationFileRequestMail($declaration, $invitation, $body)),
            'confirmation' => Mail::to($clientEmail)->send(new DeclarationConfirmationMail($declaration, $invitation, $body)),
            'text' => Mail::to($clientEmail)->send(new DeclarationTextMessageMail($declaration, $body, $invitation->token)),
            default => null,
        };

        return true;
    }
}
