<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreServiceRequest;
use App\Http\Requests\UpdateServiceRequest;
use App\Models\Service;
use App\Models\StaffProfile;
use App\Services\Tenancy\CurrentBusiness;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class ServiceController extends Controller
{
    public function index(Request $request, CurrentBusiness $currentBusiness): View
    {
        $business = $currentBusiness->get() ?? abort(403);
        $filters = $request->only(['q', 'category', 'status', 'staff_profile_id', 'sort']);

        $servicesQuery = Service::query()
            ->forBusiness($business)
            ->with('staffProfiles')
            ->withCount('appointments')
            ->when($filters['q'] ?? null, function (Builder $query, string $search): void {
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('name', 'like', "%{$search}%")
                        ->orWhere('category', 'like', "%{$search}%")
                        ->orWhere('description', 'like', "%{$search}%")
                        ->orWhereHas('staffProfiles', fn (Builder $staffQuery) => $staffQuery->where('name', 'like', "%{$search}%"));
                });
            })
            ->when($filters['category'] ?? null, fn (Builder $query, string $category) => $query->where('category', $category))
            ->when($filters['status'] ?? null, fn (Builder $query, string $status) => $query->where('status', $status))
            ->when($filters['staff_profile_id'] ?? null, function (Builder $query, string $staffId): void {
                $query->whereHas('staffProfiles', fn (Builder $staffQuery) => $staffQuery->whereKey($staffId));
            });

        match ($filters['sort'] ?? 'newest') {
            'name' => $servicesQuery->orderBy('name'),
            'price_asc' => $servicesQuery->orderBy('price'),
            'price_desc' => $servicesQuery->orderByDesc('price'),
            'duration_asc' => $servicesQuery->orderBy('duration_minutes'),
            default => $servicesQuery->latest(),
        };

        $services = $servicesQuery->paginate(10)->withQueryString();

        $baseQuery = Service::query()->forBusiness($business);
        $stats = [
            'total' => (clone $baseQuery)->count(),
            'active' => (clone $baseQuery)->where('status', Service::STATUS_ACTIVE)->count(),
            'average_price' => (clone $baseQuery)->avg('price') ?: 0,
            'top_service' => Service::query()
                ->forBusiness($business)
                ->withCount('appointments')
                ->orderByDesc('appointments_count')
                ->first(),
        ];

        return view('admin.services.index', [
            'services' => $services,
            'stats' => $stats,
            'filters' => $filters,
            'categories' => $this->categoryOptions($business->id),
            'staffProfiles' => $this->staffOptions($business->id),
        ]);
    }

    public function create(CurrentBusiness $currentBusiness): View
    {
        $business = $currentBusiness->get() ?? abort(403);

        return view('admin.services.create', [
            'service' => new Service(['status' => Service::STATUS_ACTIVE]),
            'categories' => $this->categoryOptions($business->id),
            'staffProfiles' => $this->staffOptions($business->id),
            'selectedStaffIds' => [],
        ]);
    }

    public function store(StoreServiceRequest $request, CurrentBusiness $currentBusiness): RedirectResponse
    {
        $business = $currentBusiness->get() ?? abort(403);
        $payload = $request->validatedPayload();
        $payload['business_id'] = $business->id;
        $payload['slug'] = Service::uniqueSlug($business->id, $payload['name']);

        if ($request->hasFile('image')) {
            $payload['image_path'] = $request->file('image')->store('services', 'public');
        }

        $service = Service::query()->create($payload);
        $this->syncStaff($service, $request->validated('staff_profile_ids', []), $business->id);

        return redirect()
            ->route('admin.services.show', $service)
            ->with('status', 'Service created successfully.');
    }

    public function show(Service $service, CurrentBusiness $currentBusiness): View
    {
        $this->authorizeService($service, $currentBusiness);

        $service->load('staffProfiles')->loadCount('appointments');
        $revenue = $service->invoiceItems()->sum('line_total');

        return view('admin.services.show', [
            'service' => $service,
            'revenue' => $revenue,
        ]);
    }

    public function edit(Service $service, CurrentBusiness $currentBusiness): View
    {
        $business = $this->authorizeService($service, $currentBusiness);
        $service->load('staffProfiles');

        return view('admin.services.edit', [
            'service' => $service,
            'categories' => $this->categoryOptions($business->id),
            'staffProfiles' => $this->staffOptions($business->id),
            'selectedStaffIds' => $service->staffProfiles->pluck('id')->all(),
        ]);
    }

    public function update(UpdateServiceRequest $request, Service $service, CurrentBusiness $currentBusiness): RedirectResponse
    {
        $business = $this->authorizeService($service, $currentBusiness);
        $payload = $request->validatedPayload();

        if ($service->name !== $payload['name']) {
            $payload['slug'] = Service::uniqueSlug($business->id, $payload['name'], $service->id);
        }

        if ($request->hasFile('image')) {
            $payload['image_path'] = $request->file('image')->store('services', 'public');
        }

        $service->update($payload);
        $this->syncStaff($service, $request->validated('staff_profile_ids', []), $business->id);

        return redirect()
            ->route('admin.services.show', $service)
            ->with('status', 'Service updated successfully.');
    }

    public function destroy(Service $service, CurrentBusiness $currentBusiness): RedirectResponse
    {
        $this->authorizeService($service, $currentBusiness);
        $service->delete();

        return redirect()
            ->route('admin.services.index')
            ->with('status', 'Service deleted successfully.');
    }

    private function authorizeService(Service $service, CurrentBusiness $currentBusiness)
    {
        $business = $currentBusiness->get() ?? abort(403);

        abort_unless((int) $service->business_id === (int) $business->id, 404);

        return $business;
    }

    private function syncStaff(Service $service, array $staffIds, int $businessId): void
    {
        $staffIds = StaffProfile::query()
            ->where('business_id', $businessId)
            ->whereIn('id', $staffIds)
            ->pluck('id')
            ->all();

        $syncPayload = collect($staffIds)->mapWithKeys(fn (int $id) => [
            $id => ['business_id' => $businessId],
        ])->all();

        $service->staffProfiles()->sync($syncPayload);
    }

    private function categoryOptions(int $businessId): array
    {
        $defaults = ['Hair Services', 'Grooming', 'Beauty', 'Spa', 'Consultation'];
        $existing = Service::query()
            ->where('business_id', $businessId)
            ->whereNotNull('category')
            ->distinct()
            ->orderBy('category')
            ->pluck('category')
            ->all();

        return collect([...$defaults, ...$existing])
            ->filter()
            ->unique()
            ->mapWithKeys(fn (string $category) => [$category => $category])
            ->all();
    }

    private function staffOptions(int $businessId)
    {
        return StaffProfile::query()
            ->where('business_id', $businessId)
            ->where('status', 'active')
            ->orderBy('name')
            ->get();
    }
}
