<?php

namespace App\Http\Controllers;

use App\Concerns\HasWorkspaceScope;
use App\Enums\ClientStatus;
use App\Enums\LegalForm;
use App\Enums\WorkspaceUserRole;
use App\Http\Requests\StoreClientRequest;
use App\Http\Requests\UpdateClientRequest;
use App\Models\Client;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class ClientController extends Controller
{
    use HasWorkspaceScope;

    protected function legalFormLabels(): array
    {
        $labels = [
            'sarl' => 'SARL',
            'sa' => 'SA',
            'snc' => 'SNC',
            'scs' => 'SCS',
            'eurl' => 'EURL',
            'sel' => 'SEL',
            'auto_entrepreneur' => 'Auto-entrepreneur',
            'entreprise_individuelle' => 'Entreprise individuelle',
            'other' => 'Autre',
        ];

        return array_intersect_key($labels, array_flip(LegalForm::getValues()));
    }

    protected function clientStatusLabels(): array
    {
        return [
            ClientStatus::Active => 'Actif',
            ClientStatus::Inactive => 'Inactif',
            ClientStatus::Suspended => 'Suspendu',
        ];
    }

    protected function serializeContacts(Client $client): array
    {
        return $client->contacts->map(fn ($c) => [
            'id' => $c->id,
            'full_name' => $c->full_name,
            'job_title' => $c->job_title,
            'email' => $c->email,
            'phone' => $c->phone,
            'is_principal' => $c->is_principal,
        ])->all();
    }

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

    /**
     * Display a listing of the clients.
     */
    public function index(Request $request): Response
    {
        $workspace = $this->currentWorkspace();
        $user = auth()->user();
        $isWorker = $this->isWorker();

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

        $query = $workspace->clients();

        if ($isWorker) {
            $query->whereHas('declarations', fn ($q) => $q->where('assigned_to', $user->id));
        }

        $clients = $query
            ->latest()
            ->paginate($perPage)
            ->through(fn (Client $client) => [
                'id' => $client->id,
                'company_name' => $client->company_name,
                'legal_form' => $client->legal_form->value,
                'ice' => $client->ice,
                'status' => $client->status?->value,
                'showUrl' => route('clients.show', $client),
                'editUrl' => route('clients.edit', $client),
                'destroyUrl' => route('clients.destroy', $client),
            ]);

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

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

        $workspace = $this->currentWorkspace();

        return Inertia::render('clients/Create', [
            'indexUrl' => route('clients.index'),
            'storeUrl' => route('clients.store'),
            'legalForms' => $this->legalFormLabels(),
            'clientStatusLabels' => $this->clientStatusLabels(),
            '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 client in storage.
     */
    public function store(StoreClientRequest $request): RedirectResponse
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $workspace = $this->currentWorkspace();
        $data = $request->validated();
        $contacts = $data['contacts'];
        unset($data['contacts']);
        $data['workspace_id'] = $workspace->id;

        $client = Client::query()->create($data);

        foreach ($contacts as $contact) {
            $client->contacts()->create($contact);
        }

        return to_route('clients.index');
    }

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

        $isWorker = $this->isWorker();
        $user = auth()->user();

        if ($isWorker) {
            $hasAssignedDeclarations = $client->declarations()
                ->where('assigned_to', $user->id)
                ->exists();

            if (! $hasAssignedDeclarations) {
                abort(404);
            }
        }

        $client->load(['internalResponsible', 'contacts']);

        $declarationsQuery = $client->declarations();

        if ($isWorker) {
            $declarationsQuery->where('assigned_to', $user->id);
        }

        $declarations = (clone $declarationsQuery)
            ->with(['assignee'])
            ->latest()
            ->limit(50)
            ->get()
            ->map(fn ($f) => [
                'id' => $f->id,
                'title' => $f->title,
                'type' => $f->type->value,
                'status' => $f->status->value,
                'due_date' => $f->due_date?->format('Y-m-d'),
                'created_at' => $f->created_at->format('Y-m-d'),
                'showUrl' => route('declarations.show', $f),
            ])
            ->values()
            ->all();

        $allDeclarations = (clone $declarationsQuery)->get();
        $stats = [
            'total' => $allDeclarations->count(),
            'by_status' => $allDeclarations->groupBy(fn ($f) => $f->status->value)
                ->map->count()
                ->all(),
            'by_type' => $allDeclarations->groupBy(fn ($f) => $f->type->value)
                ->map->count()
                ->all(),
        ];

        return Inertia::render('clients/Show', [
            'client' => [
                'id' => $client->id,
                'company_name' => $client->company_name,
                'legal_form' => $client->legal_form->value,
                'ice' => $client->ice,
                'fiscal_id' => $client->fiscal_id,
                'rc' => $client->rc,
                'cnss' => $client->cnss,
                'patente' => $client->patente,
                'contacts' => $this->serializeContacts($client),
                'internal_responsible_id' => $client->internal_responsible_id,
                'internal_responsible_name' => $client->internalResponsible?->name,
                'status' => $client->status?->value,
                'internal_notes' => $client->internal_notes,
            ],
            'declarations' => $declarations,
            'stats' => $stats,
            'indexUrl' => route('clients.index'),
            'editUrl' => route('clients.edit', $client),
            'createDeclarationUrl' => route('declarations.create', ['client_id' => $client->id]),
            'canEdit' => ! $isWorker,
            'canDelete' => ! $isWorker,
        ]);
    }

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

        $this->authorizeWorkspaceAccess($client);

        $workspace = $this->currentWorkspace();

        $client->load('contacts');

        return Inertia::render('clients/Edit', [
            'client' => [
                'id' => $client->id,
                'company_name' => $client->company_name,
                'legal_form' => $client->legal_form->value,
                'ice' => $client->ice,
                'fiscal_id' => $client->fiscal_id,
                'rc' => $client->rc,
                'cnss' => $client->cnss,
                'patente' => $client->patente,
                'contacts' => $this->serializeContacts($client),
                'internal_responsible_id' => $client->internal_responsible_id,
                'status' => $client->status?->value,
                'internal_notes' => $client->internal_notes,
            ],
            'indexUrl' => route('clients.index'),
            'updateUrl' => route('clients.update', $client),
            'legalForms' => $this->legalFormLabels(),
            'clientStatusLabels' => $this->clientStatusLabels(),
            '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 client in storage.
     */
    public function update(UpdateClientRequest $request, Client $client): RedirectResponse
    {
        if ($this->isWorker()) {
            abort(404);
        }

        $this->authorizeWorkspaceAccess($client);

        $data = $request->validated();
        $contacts = $data['contacts'];
        unset($data['contacts']);

        DB::transaction(function () use ($client, $data, $contacts) {
            $client->update($data);

            $submittedIds = collect($contacts)
                ->pluck('id')
                ->filter()
                ->all();

            $client->contacts()
                ->whereNotIn('id', $submittedIds)
                ->get()
                ->each
                ->delete();

            foreach ($contacts as $contactData) {
                if (! empty($contactData['id'])) {
                    $client->contacts()
                        ->where('id', $contactData['id'])
                        ->first()
                        ?->update($contactData);
                } else {
                    $client->contacts()->create($contactData);
                }
            }
        });

        return to_route('clients.index');
    }

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

        $this->authorizeWorkspaceAccess($client);

        $client->delete();

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