<?php

namespace App\Http\Controllers;

use App\Models\Company;
use App\Models\Contact;
use App\Models\User;
use App\Support\CrmModuleManager;
use Illuminate\Http\UploadedFile;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;

class ContactController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(Contact::class, 'contact');
    }

    public function index(Request $request): View
    {
        $search = trim((string) $request->input('q', ''));

        $contacts = Contact::query()
            ->with(['company', 'owner'])
            ->withCount(['deals', 'tasks'])
            ->when($search !== '', function ($query) use ($search): void {
                $query->where(function ($sub) use ($search): void {
                    $sub->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                });
            })
            ->latest()
            ->paginate(15)
            ->withQueryString();

        return view('contacts.index', compact('contacts', 'search'));
    }

    public function create(): View
    {
        $companies = Company::query()->orderBy('name')->get();
        $owners = User::query()->orderBy('name')->get();

        return view('contacts.create', compact('companies', 'owners'));
    }

    public function store(Request $request, CrmModuleManager $moduleManager): RedirectResponse
    {
        $validated = $this->validatedData($request);
        $validated = $moduleManager->applyPayloadHooks('contacts.store', $validated, [
            'hook' => 'contacts.store',
            'user_id' => $request->user()->id,
        ], array_keys($validated));
        $avatar = $request->file('avatar');

        $contact = Contact::create(Arr::except($validated, ['avatar', 'remove_avatar']));
        if ($avatar instanceof UploadedFile) {
            $contact->avatar_path = $avatar->store('contact-avatars', 'public');
            $contact->save();
        }

        return redirect()
            ->route('contacts.show', $contact)
            ->with('success', 'The contact has been created.');
    }

    public function show(Request $request, Contact $contact): View
    {
        $contact->load([
            'company',
            'owner',
            'deals.stage',
            'deals.owner',
            'tasks.assignee',
            'activities.user',
        ]);

        if ($request->boolean('sidepanel') || $request->header('X-Sidepanel') === '1') {
            return view('sidepanel.contacts.show', compact('contact'));
        }

        return view('contacts.show', compact('contact'));
    }

    public function edit(Contact $contact): View
    {
        $companies = Company::query()->orderBy('name')->get();
        $owners = User::query()->orderBy('name')->get();

        return view('contacts.edit', compact('contact', 'companies', 'owners'));
    }

    public function update(Request $request, Contact $contact, CrmModuleManager $moduleManager): RedirectResponse
    {
        $validated = $this->validatedData($request);
        $validated = $moduleManager->applyPayloadHooks('contacts.update', $validated, [
            'hook' => 'contacts.update',
            'user_id' => $request->user()->id,
            'contact_id' => $contact->id,
        ], array_keys($validated));
        $avatar = $request->file('avatar');
        $removeAvatar = $request->boolean('remove_avatar');

        $contact->update(Arr::except($validated, ['avatar', 'remove_avatar']));
        $this->syncAvatar($contact, $avatar, $removeAvatar);

        return redirect()
            ->route('contacts.show', $contact)
            ->with('success', 'Contact updated.');
    }

    public function destroy(Contact $contact): RedirectResponse
    {
        $this->deleteAvatarIfExists($contact->avatar_path);
        $contact->delete();

        return redirect()
            ->route('contacts.index')
            ->with('success', 'The contact has been deleted.');
    }

    /**
     * @return array<string, mixed>
     */
    private function validatedData(Request $request): array
    {
        return $request->validate([
            'first_name' => ['required', 'string', 'max:255'],
            'last_name' => ['nullable', 'string', 'max:255'],
            'title' => ['nullable', 'string', 'max:255'],
            'email' => ['nullable', 'email', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'company_id' => ['nullable', 'exists:companies,id'],
            'owner_id' => ['nullable', 'exists:users,id'],
            'source' => ['nullable', 'string', 'max:255'],
            'last_contacted_at' => ['nullable', 'date'],
            'notes' => ['nullable', 'string'],
            'avatar' => ['nullable', 'image', 'max:10240'],
            'remove_avatar' => ['nullable', 'boolean'],
        ]);
    }

    private function syncAvatar(Contact $contact, ?UploadedFile $avatar, bool $removeAvatar): void
    {
        $oldPath = $contact->avatar_path;

        if ($removeAvatar) {
            $contact->avatar_path = null;
        }

        if ($avatar instanceof UploadedFile) {
            $contact->avatar_path = $avatar->store('contact-avatars', 'public');
        }

        $contact->save();

        if (
            is_string($oldPath)
            && $oldPath !== ''
            && $oldPath !== $contact->avatar_path
        ) {
            $this->deleteAvatarIfExists($oldPath);
        }
    }

    private function deleteAvatarIfExists(?string $path): void
    {
        if (! is_string($path) || trim($path) === '') {
            return;
        }

        Storage::disk('public')->delete($path);
    }
}
