<?php

namespace App\Http\Controllers;

use App\Concerns\HasWorkspaceScope;
use App\Enums\DeclarationPriority;
use App\Enums\DeclarationStatus;
use App\Enums\DeclarationType;
use App\Enums\WorkspaceUserRole;
use App\Http\Requests\StoreDeclarationRequest;
use App\Http\Requests\UpdateDeclarationRequest;
use App\Models\Client;
use App\Models\Declaration;
use App\Models\MediaDownload;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class DeclarationController extends Controller
{
    use HasWorkspaceScope;

    protected function declarationTypeLabels(): array
    {
        return [
            DeclarationType::VAT => 'TVA',
            DeclarationType::VatMonthly => 'TVA mensuelle',
            DeclarationType::VatQuarterly => 'TVA trimestrielle',
            DeclarationType::CorporateTax => 'IS',
            DeclarationType::IncomeTax => 'IR',
            DeclarationType::CNSS => 'CNSS',
            DeclarationType::AnnualBalance => 'Bilan',
            DeclarationType::Other => 'Autre',
        ];
    }

    protected function declarationStatusLabels(): array
    {
        return DeclarationStatus::labels();
    }

    protected function declarationPriorityLabels(): array
    {
        return [
            DeclarationPriority::Low => 'Basse',
            DeclarationPriority::Medium => 'Normale',
            DeclarationPriority::High => 'Haute',
        ];
    }

    protected function isWorker(): bool
    {
        return auth()->user()->currentWorkspaceUser()->role->is(WorkspaceUserRole::Worker);
    }

    /**
     * Display a listing of the declarations.
     */
    public function index(Request $request): Response
    {
        $workspace = $this->currentWorkspace();
        $user = auth()->user();
        $workspaceUser = $user->currentWorkspaceUser();
        $isWorker = $workspaceUser->role->is(WorkspaceUserRole::Worker);

        $perPage = min(max((int) $request->input('per_page', 10), 10), 100);

        $declarations = $workspace->declarations()
            ->forUser($user, $workspaceUser)
            ->with(['client', 'assignee'])
            ->latest()
            ->paginate($perPage)
            ->through(fn (Declaration $declaration) => [
                'id' => $declaration->id,
                'title' => $declaration->title,
                'type' => $declaration->type->value,
                'client_name' => $declaration->client->company_name,
                'assignee_name' => $declaration->assignee?->name,
                'status' => $declaration->status->value,
                'due_date' => $declaration->due_date?->format('Y-m-d'),
                'showUrl' => route('declarations.show', $declaration),
                'editUrl' => route('declarations.edit', $declaration),
                'destroyUrl' => route('declarations.destroy', $declaration),
                'nudgeUrl' => ! $isWorker ? route('declarations.nudge', $declaration) : null,
            ]);

        return Inertia::render('declarations/Index', [
            'declarations' => $declarations,
            'createUrl' => route('declarations.create'),
            'workspaceName' => $workspace->name,
            'canCreate' => ! $isWorker,
            'canEdit' => ! $isWorker,
            'canDelete' => ! $isWorker,
            'canNudge' => ! $isWorker,
        ]);
    }

    /**
     * Show the form for creating a new declaration.
     */
    public function create(Request $request): Response
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $workspace = $this->currentWorkspace();
        $initialClientId = $request->integer('client_id', 0) ?: null;

        return Inertia::render('declarations/Create', [
            'indexUrl' => route('declarations.index'),
            'storeUrl' => route('declarations.store'),
            'initialClientId' => $initialClientId,
            'declarationTypeLabels' => $this->declarationTypeLabels(),
            'declarationStatusLabels' => $this->declarationStatusLabels(),
            'declarationPriorityLabels' => $this->declarationPriorityLabels(),
            'clients' => $workspace->clients()->orderBy('company_name')->get(['id', 'company_name'])->map(fn (Client $c) => [
                'id' => $c->id,
                'company_name' => $c->company_name,
            ])->values()->all(),
            'workspaceUsers' => $workspace->users()
                ->orderBy('users.name')
                ->select('users.id', 'users.name', 'users.email')
                ->get()
                ->map(fn ($u) => [
                    'id' => $u->id,
                    'name' => $u->name,
                    'email' => $u->email,
                ])->values()->all(),
        ]);
    }

    /**
     * Store a newly created declaration in storage.
     */
    public function store(StoreDeclarationRequest $request): RedirectResponse
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $workspace = $this->currentWorkspace();
        $data = $request->validated();
        $data['workspace_id'] = $workspace->id;
        $data['created_by'] = $request->user()?->id;
        $data['status'] = $data['status'] ?? DeclarationStatus::Created;

        if (($data['type'] ?? '') === 'vat_monthly') {
            $data['period_quarter'] = null;
        } elseif (($data['type'] ?? '') === 'vat_quarterly') {
            $data['period_month'] = null;
        }

        Declaration::query()->create($data);

        return to_route('declarations.index');
    }

    /**
     * Display the specified declaration.
     */
    public function show(Request $request, Declaration $declaration): Response
    {
        $this->authorizeWorkspaceAccess($declaration);

        $workspace = $this->currentWorkspace();
        $user = auth()->user();
        $workspaceUser = $user->currentWorkspaceUser();
        $isWorker = $workspaceUser->role->is(WorkspaceUserRole::Worker);

        if ($isWorker && $declaration->assigned_to !== $user->id) {
            abort(404);
        }

        $declaration->load(['client', 'creator', 'assignee', 'messages' => fn ($q) => $q->with(['senderUser', 'senderClient'])->latest()]);

        $allMedia = $declaration->getMedia('documents');
        $downloadedMediaIds = MediaDownload::query()
            ->where('user_id', $request->user()->id)
            ->whereIn('media_id', $allMedia->pluck('id'))
            ->pluck('media_id')
            ->all();

        $messages = $declaration->messages->map(function ($m) use ($declaration, $allMedia, $downloadedMediaIds) {
            $attachments = $allMedia
                ->filter(fn ($media) => $media->getCustomProperty('message_id') === $m->id)
                ->map(fn ($media) => [
                    'id' => $media->id,
                    'file_name' => $media->file_name,
                    'mime_type' => $media->mime_type,
                    'size' => $media->human_readable_size,
                    'downloadUrl' => route('declarations.media.download', ['declaration' => $declaration, 'mediaId' => $media->id]),
                    'is_downloaded' => in_array($media->id, $downloadedMediaIds),
                ])
                ->values()
                ->all();

            $confirmationStatus = null;
            if ($m->type->value === 'confirmation') {
                $confirmationStatus = $declaration->refused_at ? 'refused' : ($declaration->validated_at ? 'confirmed' : 'pending');
            }

            return [
                'id' => $m->id,
                'type' => $m->type->value,
                'body' => $m->body,
                'sent_by_type' => $m->sent_by_type->value,
                'sender_name' => $m->sender_name,
                'created_at' => $m->created_at->format('Y-m-d H:i'),
                'attachments' => $attachments,
                'confirmation_status' => $confirmationStatus,
            ];
        })->values()->all();

        $documents = $allMedia->map(fn ($m) => [
            'id' => $m->id,
            'name' => $m->name,
            'file_name' => $m->file_name,
            'size' => $m->human_readable_size,
            'created_at' => $m->created_at->format('d/m/Y H:i'),
            'uploaded_by' => $m->getCustomProperty('uploaded_by_type') === 'user' ? 'Comptable' : 'Client',
            'downloadUrl' => route('declarations.media.download', ['declaration' => $declaration, 'mediaId' => $m->id]),
            'is_downloaded' => in_array($m->id, $downloadedMediaIds),
        ])->values()->all();

        $canMention = ! $isWorker;

        return Inertia::render('declarations/Show', [
            'declaration' => [
                'id' => $declaration->id,
                'title' => $declaration->title,
                'type' => $declaration->type->value,
                'client_id' => $declaration->client_id,
                'client_name' => $declaration->client->company_name,
                'period_year' => $declaration->period_year,
                'period_month' => $declaration->period_month,
                'period_quarter' => $declaration->period_quarter,
                'due_date' => $declaration->due_date?->format('Y-m-d'),
                'status' => $declaration->status->value,
                'priority' => $declaration->priority?->value,
                'assigned_to' => $declaration->assigned_to,
                'assignee_name' => $declaration->assignee?->name,
                'validated_at' => $declaration->validated_at?->format('Y-m-d H:i'),
                'closed_at' => $declaration->closed_at?->format('Y-m-d H:i'),
                'notes_internal' => $declaration->notes_internal,
                'notes_client' => $declaration->notes_client,
                'created_at' => $declaration->created_at?->format('Y-m-d H:i'),
            ],
            'messages' => $messages,
            'documents' => $documents,
            'messagesStoreUrl' => route('declarations.messages.store', $declaration),
            'mediaStoreUrl' => route('declarations.media.store', $declaration),
            'messageTypeLabels' => [
                'invite' => 'Invitation',
                'situation' => 'Situation',
                'file_request' => 'Demande de pièces',
                'confirmation' => 'Demande de validation',
                'text' => 'Message',
            ],
            'indexUrl' => route('declarations.index'),
            'editUrl' => route('declarations.edit', $declaration),
            'workspaceUsers' => $workspace->users()->orderBy('users.name')
                ->select('users.id', 'users.name', 'users.email')
                ->get()->map(fn ($u) => ['id' => $u->id, 'name' => $u->name])
                ->values()->all(),
            'mentionStoreUrl' => route('declarations.mentions.store', $declaration),
            'canMention' => $canMention,
            'canEdit' => ! $isWorker,
            'canDelete' => ! $isWorker,
        ]);
    }

    /**
     * Show the form for editing the specified declaration.
     */
    public function edit(Request $request, Declaration $declaration): Response
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $this->authorizeWorkspaceAccess($declaration);

        $workspace = $this->currentWorkspace();

        return Inertia::render('declarations/Edit', [
            'declaration' => [
                'id' => $declaration->id,
                'title' => $declaration->title,
                'type' => $declaration->type->value,
                'client_id' => $declaration->client_id,
                'period_year' => $declaration->period_year,
                'period_month' => $declaration->period_month,
                'period_quarter' => $declaration->period_quarter,
                'due_date' => $declaration->due_date?->format('Y-m-d'),
                'status' => $declaration->status->value,
                'priority' => $declaration->priority?->value,
                'assigned_to' => $declaration->assigned_to,
                'notes_internal' => $declaration->notes_internal,
                'notes_client' => $declaration->notes_client,
                'created_at' => $declaration->created_at?->format('Y-m-d H:i'),
            ],
            'indexUrl' => route('declarations.index'),
            'updateUrl' => route('declarations.update', $declaration),
            'declarationTypeLabels' => $this->declarationTypeLabels(),
            'declarationStatusLabels' => $this->declarationStatusLabels(),
            'declarationPriorityLabels' => $this->declarationPriorityLabels(),
            'clients' => $workspace->clients()->orderBy('company_name')->get(['id', 'company_name'])->map(fn (Client $c) => [
                'id' => $c->id,
                'company_name' => $c->company_name,
            ])->values()->all(),
            'workspaceUsers' => $workspace->users()
                ->orderBy('users.name')
                ->select('users.id', 'users.name', 'users.email')
                ->get()
                ->map(fn ($u) => [
                    'id' => $u->id,
                    'name' => $u->name,
                    'email' => $u->email,
                ])->values()->all(),
        ]);
    }

    /**
     * Update the specified declaration in storage.
     */
    public function update(UpdateDeclarationRequest $request, Declaration $declaration): RedirectResponse
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $this->authorizeWorkspaceAccess($declaration);

        $data = $request->validated();

        if (($data['type'] ?? '') === 'vat_monthly') {
            $data['period_quarter'] = null;
        } elseif (($data['type'] ?? '') === 'vat_quarterly') {
            $data['period_month'] = null;
        }

        $declaration->update($data);

        return to_route('declarations.index');
    }

    /**
     * Remove the specified declaration from storage.
     */
    public function destroy(Request $request, Declaration $declaration): RedirectResponse
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $this->authorizeWorkspaceAccess($declaration);

        $declaration->delete();

        return to_route('declarations.index');
    }
}
