<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\MariachiGroup;
use App\Models\Serenata;
use App\Support\OwnerWorkspace;
use App\Support\PhoneNumber;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Validation\Rule;

class ClientController extends Controller
{
    private function normalizeName(string $name): string
    {
        return mb_strtolower(trim(preg_replace('/\s+/', ' ', $name) ?? ''), 'UTF-8');
    }

    private function syncCustomersFromSerenatas(int $organizationId, ?array $accessibleGroupIds = null): void
    {
        $serenataQuery = Serenata::query()
            ->where('organization_id', $organizationId)
            ->whereNotNull('payer_name')
            ->where('payer_name', '!=', '')
            ->select([
                'id',
                'mariachi_group_id',
                'payer_name',
                'payer_email',
                'contact_phone_1',
                'service_address',
                'address_additional',
                'locality',
            ]);

        if ($accessibleGroupIds !== null) {
            if (empty($accessibleGroupIds)) {
                return;
            }

            $serenataQuery->whereIn('mariachi_group_id', $accessibleGroupIds);
        }

        $serenatas = $serenataQuery->get();

        foreach ($serenatas as $serenata) {
            $payerName = trim((string) $serenata->payer_name);
            if ($payerName === '') {
                continue;
            }

            $payerKey = $this->normalizeName($payerName);
            if ($payerKey === '') {
                continue;
            }

            $customer = Customer::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', $serenata->mariachi_group_id)
                ->whereRaw('LOWER(TRIM(name)) = ?', [$payerKey])
                ->first();

            if (!$customer) {
                $customer = Customer::create([
                    'organization_id' => $organizationId,
                    'mariachi_group_id' => $serenata->mariachi_group_id,
                    'name' => $payerName,
                    'email' => trim((string) ($serenata->payer_email ?? '')) ?: null,
                    'mobile' => PhoneNumber::normalize((string) ($serenata->contact_phone_1 ?? '')) ?: null,
                    'address_line_1' => trim((string) ($serenata->service_address ?? '')) ?: null,
                    'address_line_2' => trim((string) ($serenata->address_additional ?? '')) ?: null,
                    'town' => trim((string) ($serenata->locality ?? '')) ?: null,
                    'state_province' => null,
                    'post_code' => null,
                    'country' => 'Colombia',
                    'is_billing_same' => true,
                    'is_active' => true,
                ]);
            }

            Serenata::query()
                ->where('id', $serenata->id)
                ->whereNull('customer_id')
                ->update(['customer_id' => $customer->id]);

            $updates = [];
            if (empty($customer->mobile) && !empty($serenata->contact_phone_1)) {
                $updates['mobile'] = PhoneNumber::normalize((string) $serenata->contact_phone_1);
            }
            if (empty($customer->email) && !empty($serenata->payer_email)) {
                $updates['email'] = trim((string) $serenata->payer_email);
            }
            if (empty($customer->address_line_1) && !empty($serenata->service_address)) {
                $updates['address_line_1'] = trim((string) $serenata->service_address);
            }
            if (empty($customer->address_line_2) && !empty($serenata->address_additional)) {
                $updates['address_line_2'] = trim((string) $serenata->address_additional);
            }
            if (empty($customer->town) && !empty($serenata->locality)) {
                $updates['town'] = trim((string) $serenata->locality);
            }
            if (empty($customer->country)) {
                $updates['country'] = 'Colombia';
            }
            if (!empty($updates)) {
                $customer->update($updates);
            }
        }
    }

    public function index(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        $canManage = $organizationId > 0;
        $activeGroupId = $canManage ? OwnerWorkspace::activeGroupId($request, $organizationId) : null;
        $accessibleGroupIds = OwnerWorkspace::accessibleGroupIds($request->user());

        if ($canManage) {
            MariachiGroup::ensureDefaultForOrganization($organizationId);
            $this->syncCustomersFromSerenatas($organizationId, $accessibleGroupIds);
        }

        $customers = $canManage
            ? OwnerWorkspace::applyScope(
                Customer::query()->where('organization_id', $organizationId),
                $request
            )
                ->with('mariachiGroup:id,name')
                ->orderByDesc('id')
                ->get()
            : collect();

        $orderStats = collect();
        if ($canManage) {
            $orderStats = OwnerWorkspace::applyScope(
                Serenata::query()
                ->where('organization_id', $organizationId)
                ->whereNotNull('customer_id'),
                $request
            )
                ->selectRaw('customer_id, COUNT(*) as orders_count, SUM(total_charged) as total_spent')
                ->groupBy('customer_id')
                ->get()
                ->keyBy('customer_id');
        }

        $stats = [
            'total' => $customers->count(),
            'active' => $customers->where('is_active', true)->count(),
            'with_email' => $customers->filter(fn ($c) => !empty($c->email))->count(),
            'countries' => $customers->pluck('country')->filter()->unique()->count(),
        ];

        return view('content.owner.clients.index', [
            'canManageClients' => $canManage,
            'customers' => $customers,
            'orderStats' => $orderStats,
            'stats' => $stats,
            'mariachiGroupOptions' => $canManage
                ? OwnerWorkspace::groupsForUser($request->user())
                : collect(),
            'selectedWorkspaceGroupId' => $activeGroupId,
        ]);
    }

    public function store(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0) {
            return redirect()->route('owner.clients.index')->withErrors([
                'name' => 'Primero debes tener una organización asignada.',
            ]);
        }

        $validated = $request->validate([
            'mariachi_group_id' => ['nullable', 'integer', 'min:1'],
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'nullable',
                'string',
                'lowercase',
                'email',
                'max:255',
                Rule::unique('customers', 'email')->where(fn ($q) => $q->where('organization_id', $organizationId)),
            ],
            'mobile' => ['nullable', 'string', 'max:40'],
            'address_line_1' => ['nullable', 'string', 'max:255'],
            'address_line_2' => ['nullable', 'string', 'max:255'],
            'town' => ['nullable', 'string', 'max:120'],
            'state_province' => ['nullable', 'string', 'max:120'],
            'post_code' => ['nullable', 'string', 'max:20'],
            'country' => ['nullable', 'string', 'max:120'],
            'is_billing_same' => ['nullable', 'boolean'],
            'is_active' => ['required', 'boolean'],
        ]);

        $mariachiGroupId = (int) ($validated['mariachi_group_id'] ?? 0);
        if ($mariachiGroupId <= 0) {
            $mariachiGroupId = (int) (MariachiGroup::ensureDefaultForOrganization($organizationId)?->id ?? 0);
        }

        $groupExists = OwnerWorkspace::canAccessGroup($request->user(), $mariachiGroupId);
        if (!$groupExists) {
            return redirect()->route('owner.clients.index')->withErrors([
                'mariachi_group_id' => 'Selecciona un grupo musical válido.',
            ]);
        }

        $validated['organization_id'] = $organizationId;
        $validated['mariachi_group_id'] = $mariachiGroupId;
        $validated['mobile'] = PhoneNumber::normalize((string) ($validated['mobile'] ?? '')) ?: null;
        $validated['is_billing_same'] = (bool) ($validated['is_billing_same'] ?? true);

        Customer::create($validated);

        return redirect()->route('owner.clients.index')->with('status', 'Cliente creado correctamente.');
    }

    public function deactivate(Request $request, Customer $customer)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if (
            $organizationId <= 0
            || $customer->organization_id !== $organizationId
            || !OwnerWorkspace::canAccessGroup($request->user(), (int) $customer->mariachi_group_id)
        ) {
            abort(404);
        }

        $customer->update(['is_active' => false]);

        return redirect()->route('owner.clients.index')->with('status', 'Cliente desactivado correctamente.');
    }

    public function show(Request $request, Customer $customer)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if (
            $organizationId <= 0
            || $customer->organization_id !== $organizationId
            || !OwnerWorkspace::canAccessGroup($request->user(), (int) $customer->mariachi_group_id)
        ) {
            abort(404);
        }

        $customer->loadMissing('mariachiGroup');

        $this->syncCustomersFromSerenatas($organizationId, OwnerWorkspace::accessibleGroupIds($request->user()));

        $serenataQuery = Serenata::query()
            ->where('organization_id', $organizationId)
            ->where(function ($q) use ($customer) {
                $q->where('customer_id', $customer->id)
                    ->orWhere(function ($query) use ($customer) {
                        $query->whereRaw('LOWER(TRIM(payer_name)) = ?', [$this->normalizeName($customer->name)])
                            ->where('mariachi_group_id', $customer->mariachi_group_id);
                    });
            })
            ->orderByDesc('event_date')
            ->orderByDesc('event_time')
            ->orderByDesc('id');

        $serenatas = OwnerWorkspace::applyScope($serenataQuery, $request)
            ->paginate(10, ['*'], 'serenatas_page')
            ->fragment('customer-serenatas');

        $addressBookCollection = OwnerWorkspace::applyScope(
            Serenata::query()
                ->where('organization_id', $organizationId)
                ->where(function ($q) use ($customer) {
                    $q->where('customer_id', $customer->id)
                        ->orWhere(function ($query) use ($customer) {
                            $query->whereRaw('LOWER(TRIM(payer_name)) = ?', [$this->normalizeName($customer->name)])
                                ->where('mariachi_group_id', $customer->mariachi_group_id);
                        });
                }),
            $request
        )
            ->orderByDesc('event_date')
            ->orderByDesc('event_time')
            ->get()
            ->map(function (Serenata $item) {
                return trim(
                    implode(', ', array_filter([
                        trim((string) $item->service_address),
                        trim((string) ($item->address_additional ?? '')),
                        trim((string) $item->locality),
                    ]))
                );
            })
            ->filter()
            ->unique()
            ->values();

        $addressPage = max(1, (int) $request->query('addresses_page', 1));
        $addressPerPage = 10;
        $addressBook = new LengthAwarePaginator(
            $addressBookCollection->forPage($addressPage, $addressPerPage)->values(),
            $addressBookCollection->count(),
            $addressPerPage,
            $addressPage,
            [
                'path' => $request->url(),
                'pageName' => 'addresses_page',
            ]
        );
        $addressBook->fragment('customer-addresses');

        $stats = [
            'orders' => (int) $serenatas->total(),
            'spent' => (float) OwnerWorkspace::applyScope(
                Serenata::query()
                    ->where('organization_id', $organizationId)
                    ->where(function ($q) use ($customer) {
                        $q->where('customer_id', $customer->id)
                            ->orWhere(function ($query) use ($customer) {
                                $query->whereRaw('LOWER(TRIM(payer_name)) = ?', [$this->normalizeName($customer->name)])
                                    ->where('mariachi_group_id', $customer->mariachi_group_id);
                            });
                    }),
                $request
            )->sum('total_charged'),
            'last_order_at' => optional(
                OwnerWorkspace::applyScope(
                    Serenata::query()
                        ->where('organization_id', $organizationId)
                        ->where(function ($q) use ($customer) {
                            $q->where('customer_id', $customer->id)
                                ->orWhere(function ($query) use ($customer) {
                                    $query->whereRaw('LOWER(TRIM(payer_name)) = ?', [$this->normalizeName($customer->name)])
                                        ->where('mariachi_group_id', $customer->mariachi_group_id);
                                });
                        })
                        ->latest('event_date')
                        ->latest('event_time')
                        ->latest('id'),
                    $request
                )->first()
            )->created_at,
        ];

        return view('content.owner.clients.show', [
            'customer' => $customer,
            'serenatas' => $serenatas,
            'addressBook' => $addressBook,
            'stats' => $stats,
        ]);
    }
}
