<?php

namespace App\Http\Controllers;

use App\Models\Company;
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 CompanyController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(Company::class, 'company');
    }

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

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

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

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

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

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

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

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

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

        return view('companies.show', compact('company'));
    }

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

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

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

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

        return redirect()
            ->route('companies.show', $company)
            ->with('success', 'The company has been updated.');
    }

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

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

    /**
     * @return array<string, mixed>
     */
    private function validatedData(Request $request): array
    {
        return $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'industry' => ['nullable', 'string', 'max:255'],
            'website' => ['nullable', 'url', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'email' => ['nullable', 'email', 'max:255'],
            'address' => ['nullable', 'string'],
            'owner_id' => ['nullable', 'exists:users,id'],
            'source' => ['nullable', 'string', 'max:255'],
            'status' => ['required', 'in:lead,client,partner,inactive'],
            'notes' => ['nullable', 'string'],
            'avatar' => ['nullable', 'image', 'max:10240'],
            'remove_avatar' => ['nullable', 'boolean'],
        ]);
    }

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

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

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

        $company->save();

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

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

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