<?php

namespace Database\Seeders;

use App\Enums\AppointmentStatus;
use App\Enums\InvoiceStatus;
use App\Enums\PaymentStatus;
use App\Enums\ReminderStatus;
use App\Enums\SubscriptionStatus;
use App\Enums\SupportTicketStatus;
use App\Models\ActivityLog;
use App\Models\Appointment;
use App\Models\AppointmentStatusLog;
use App\Models\Business;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Language;
use App\Models\Payment;
use App\Models\Plan;
use App\Models\ReminderLog;
use App\Models\ReminderTemplate;
use App\Models\ScheduledReminder;
use App\Models\Service;
use App\Models\Setting;
use App\Models\StaffBreak;
use App\Models\StaffProfile;
use App\Models\Subscription;
use App\Models\SubscriptionPayment;
use App\Models\SupportTicket;
use App\Models\Translation;
use App\Models\User;
use App\Services\Localization\LanguageService;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;

class CoreDemoSeeder extends Seeder
{
    public function run(): void
    {
        $plans = $this->seedPlans();
        $this->seedLanguages();

        Business::query()->each(function (Business $business) use ($plans): void {
            $this->seedSubscription($business, $plans);
            $services = $this->seedServices($business);
            $staff = $this->seedStaff($business, $services);
            $customers = $this->seedCustomers($business);
            $appointments = $this->seedAppointments($business, $services, $staff, $customers);
            $invoices = $this->seedInvoices($business, $appointments, $services, $customers);
            $this->seedReminders($business, $appointments, $invoices, $customers);
            $this->seedSettings($business);
            $this->seedActivityAndSupport($business);
        });
    }

    private function seedPlans()
    {
        $plans = [
            ['name' => 'Free Trial', 'slug' => 'free-trial', 'monthly_price' => 0, 'yearly_price' => 0, 'trial_days' => 14, 'max_staff' => 3, 'max_services' => 8, 'max_appointments_per_month' => 50, 'max_reminders_per_month' => 100, 'max_invoices_per_month' => 25, 'invoice_module_enabled' => true, 'email_reminder_enabled' => true],
            ['name' => 'Starter', 'slug' => 'starter', 'monthly_price' => 19, 'yearly_price' => 190, 'trial_days' => 7, 'max_staff' => 5, 'max_services' => 20, 'max_appointments_per_month' => 300, 'max_reminders_per_month' => 1000, 'max_invoices_per_month' => 100, 'invoice_module_enabled' => true, 'email_reminder_enabled' => true],
            ['name' => 'Professional', 'slug' => 'professional', 'monthly_price' => 39, 'yearly_price' => 390, 'trial_days' => 14, 'max_staff' => 15, 'max_services' => 80, 'max_appointments_per_month' => 1500, 'max_reminders_per_month' => 5000, 'max_invoices_per_month' => 500, 'invoice_module_enabled' => true, 'whatsapp_reminder_enabled' => true, 'email_reminder_enabled' => true, 'reports_enabled' => true, 'custom_branding_enabled' => true],
            ['name' => 'Agency', 'slug' => 'agency', 'monthly_price' => 79, 'yearly_price' => 790, 'trial_days' => 14, 'max_staff' => null, 'max_services' => null, 'max_appointments_per_month' => null, 'max_reminders_per_month' => null, 'max_invoices_per_month' => null, 'invoice_module_enabled' => true, 'whatsapp_reminder_enabled' => true, 'email_reminder_enabled' => true, 'reports_enabled' => true, 'custom_branding_enabled' => true],
        ];

        return collect($plans)->mapWithKeys(function (array $plan, int $index) {
            $model = Plan::query()->updateOrCreate(
                ['slug' => $plan['slug']],
                array_merge([
                    'description' => "Booklio {$plan['name']} demo plan.",
                    'status' => 'active',
                    'sort_order' => $index + 1,
                    'whatsapp_reminder_enabled' => false,
                    'reports_enabled' => false,
                    'custom_branding_enabled' => false,
                ], $plan)
            );

            return [$plan['slug'] => $model];
        });
    }

    private function seedLanguages(): void
    {
        app(LanguageService::class)->ensureDefaults(fillMissingTranslations: true);

        return;

        $languages = [
            ['name' => 'English', 'native_name' => 'English', 'code' => 'en', 'direction' => 'ltr', 'is_default' => true],
            ['name' => 'Arabic', 'native_name' => 'العربية', 'code' => 'ar', 'direction' => 'rtl', 'is_default' => false],
            ['name' => 'Urdu', 'native_name' => 'اردو', 'code' => 'ur', 'direction' => 'rtl', 'is_default' => false],
        ];

        foreach ($languages as $index => $language) {
            $model = Language::query()->updateOrCreate(
                ['code' => $language['code']],
                array_merge($language, ['is_active' => true, 'sort_order' => $index + 1])
            );

            foreach (['dashboard' => 'Dashboard', 'appointments' => 'Appointments', 'settings' => 'Settings'] as $key => $default) {
                Translation::query()->updateOrCreate(
                    ['language_id' => $model->id, 'module' => 'dashboard', 'translation_key' => $key],
                    [
                        'default_text' => $default,
                        'translated_text' => $language['code'] === 'en' ? $default : null,
                        'is_missing' => $language['code'] !== 'en',
                    ]
                );
            }
        }
    }

    private function seedSubscription(Business $business, $plans): void
    {
        $plan = match ($business->slug) {
            'prime-dental-clinic' => $plans['agency'],
            'cleanpro-services' => $plans['starter'],
            default => $plans['professional'],
        };

        $subscription = Subscription::query()->updateOrCreate(
            ['business_id' => $business->id, 'plan_id' => $plan->id],
            [
                'status' => $business->status === 'active' ? SubscriptionStatus::Active->value : SubscriptionStatus::Trial->value,
                'billing_cycle' => $business->slug === 'prime-dental-clinic' ? 'yearly' : 'monthly',
                'starts_at' => now()->subDays(21),
                'trial_ends_at' => $business->status === 'trial' ? now()->addDays(14) : now()->subDays(7),
                'renews_at' => now()->addMonth(),
                'price' => $business->slug === 'prime-dental-clinic' ? $plan->yearly_price : $plan->monthly_price,
                'currency' => 'USD',
                'gateway' => $business->status === 'active' ? 'stripe' : null,
                'usage_snapshot' => ['staff' => 3, 'services' => 5, 'appointments' => 18, 'reminders' => 42, 'invoices' => 8],
            ]
        );

        if ($business->status === 'active') {
            SubscriptionPayment::query()->updateOrCreate(
                ['transaction_id' => 'sub_'.$business->slug],
                [
                    'business_id' => $business->id,
                    'subscription_id' => $subscription->id,
                    'plan_id' => $plan->id,
                    'amount' => $subscription->price,
                    'currency' => 'USD',
                    'payment_method' => 'stripe',
                    'status' => PaymentStatus::Paid->value,
                    'paid_at' => now()->subDays(3),
                ]
            );
        }
    }

    private function seedServices(Business $business)
    {
        $items = match ($business->slug) {
            'prime-dental-clinic' => [
                ['Dental Checkup', 'Dental', 85, 45],
                ['Teeth Cleaning', 'Dental', 120, 60],
                ['Whitening Consultation', 'Cosmetic', 65, 30],
            ],
            'cleanpro-services' => [
                ['Home Cleaning', 'Residential', 95, 120],
                ['Office Cleaning', 'Commercial', 180, 180],
                ['Deep Cleaning', 'Residential', 240, 240],
            ],
            default => [
                ['Hair Cut & Style', 'Hair Services', 65, 60],
                ['Beard Trim', 'Grooming', 35, 45],
                ['Facial Treatment', 'Beauty', 80, 60],
                ['Hair Color', 'Hair Services', 120, 90],
                ['Manicure', 'Beauty', 45, 60],
            ],
        };

        return collect($items)->mapWithKeys(function (array $item) use ($business) {
            [$name, $category, $price, $duration] = $item;

            $service = Service::query()->updateOrCreate(
                ['business_id' => $business->id, 'slug' => Str::slug($name)],
                [
                    'name' => $name,
                    'category' => $category,
                    'price' => $price,
                    'duration_minutes' => $duration,
                    'description' => "{$name} demo service for {$business->name}.",
                    'buffer_before_minutes' => 10,
                    'buffer_after_minutes' => 10,
                    'status' => 'active',
                ]
            );

            return [$service->slug => $service];
        });
    }

    private function seedStaff(Business $business, $services)
    {
        $owner = $business->owner;
        $staffUser = User::query()->where('email', 'staff@booklio.test')->first();

        $profiles = [
            ['user' => $business->slug === 'glow-beauty-salon' ? $staffUser : null, 'name' => $business->slug === 'glow-beauty-salon' ? 'Emma Wilson' : 'Primary Specialist', 'role' => 'Senior Specialist', 'color' => '#2563EB'],
            ['user' => null, 'name' => $business->slug === 'prime-dental-clinic' ? 'Dr. Adam Reed' : 'James Smith', 'role' => $business->slug === 'prime-dental-clinic' ? 'Dentist' : 'Specialist', 'color' => '#0EA5E9'],
            ['user' => null, 'name' => $business->slug === 'cleanpro-services' ? 'Nora Evans' : 'Olivia Brown', 'role' => 'Service Expert', 'color' => '#10B981'],
        ];

        return collect($profiles)->map(function (array $profile, int $index) use ($business, $services, $owner) {
            $user = $profile['user'] ?: ($index === 1 ? $owner : null);

            $staff = StaffProfile::query()->updateOrCreate(
                ['business_id' => $business->id, 'name' => $profile['name']],
                [
                    'user_id' => $user?->id,
                    'email' => $user?->email ?? Str::slug($profile['name']).'@'.$business->slug.'.test',
                    'phone' => '+1 (555) '.random_int(100, 999).'-'.random_int(1000, 9999),
                    'role' => $profile['role'],
                    'color' => $profile['color'],
                    'status' => 'active',
                    'availability_status' => $index === 1 ? 'busy' : 'available',
                    'bio' => "Demo {$profile['role']} for {$business->name}.",
                ]
            );

            $serviceIds = $services->take($index === 0 ? 2 : 3)->pluck('id')->mapWithKeys(fn ($id) => [
                $id => ['business_id' => $business->id, 'is_primary' => false],
            ])->all();

            $staff->services()->syncWithoutDetaching($serviceIds);

            foreach (range(1, 5) as $day) {
                $staff->workingHours()->updateOrCreate(
                    ['business_id' => $business->id, 'day_of_week' => $day],
                    ['starts_at' => '09:00:00', 'ends_at' => '17:00:00', 'is_closed' => false]
                );
            }

            StaffBreak::query()->updateOrCreate(
                ['business_id' => $business->id, 'staff_profile_id' => $staff->id, 'day_of_week' => 3, 'starts_at' => '12:00:00'],
                ['title' => 'Lunch break', 'ends_at' => '12:30:00', 'is_recurring' => true]
            );

            return $staff;
        });
    }

    private function seedCustomers(Business $business)
    {
        $customers = [
            ['Jessica Miller', 'jessica@example.com', '(555) 123-4567', 'Booking page'],
            ['Michael Brown', 'michael@example.com', '(555) 234-6789', 'Walk-in'],
            ['Sophia Davis', 'sophia@example.com', '(555) 345-7890', 'Instagram'],
            ['Amanda Taylor', 'amanda@example.com', '(555) 456-8901', 'Referral'],
        ];

        return collect($customers)->mapWithKeys(function (array $customer) use ($business) {
            [$name, $email, $phone, $source] = $customer;

            $model = Customer::query()->updateOrCreate(
                ['business_id' => $business->id, 'email' => $email],
                [
                    'name' => $name,
                    'phone' => $phone,
                    'status' => $name === 'Jessica Miller' ? 'vip' : 'active',
                    'source' => $source,
                    'notes' => 'Demo CRM customer profile.',
                    'total_spent' => random_int(120, 1200),
                    'last_visit_at' => now()->subDays(random_int(1, 20)),
                ]
            );

            return [$model->email => $model];
        });
    }

    private function seedAppointments(Business $business, $services, $staff, $customers)
    {
        $rows = [
            ['BK-1001', 'jessica@example.com', AppointmentStatus::Confirmed->value, 1, 9],
            ['BK-1002', 'michael@example.com', AppointmentStatus::Completed->value, 2, 10],
            ['BK-1003', 'sophia@example.com', AppointmentStatus::Pending->value, 3, 11],
            ['BK-1004', 'amanda@example.com', AppointmentStatus::Cancelled->value, 0, 13],
        ];

        return collect($rows)->map(function (array $row, int $index) use ($business, $services, $staff, $customers) {
            [$number, $email, $status, $serviceIndex, $hour] = $row;
            $service = $services->values()->get($serviceIndex) ?? $services->first();
            $staffProfile = $staff->values()->get($index % $staff->count());
            $startsAt = now()->startOfMonth()->addDays($index + 1)->setTime($hour, 0);

            $appointment = Appointment::query()->updateOrCreate(
                ['business_id' => $business->id, 'booking_number' => $number],
                [
                    'customer_id' => $customers[$email]->id,
                    'service_id' => $service->id,
                    'staff_profile_id' => $staffProfile->id,
                    'status' => $status,
                    'starts_at' => $startsAt,
                    'ends_at' => $startsAt->copy()->addMinutes($service->duration_minutes),
                    'duration_minutes' => $service->duration_minutes,
                    'price' => $service->price,
                    'payment_status' => in_array($status, [AppointmentStatus::Completed->value, AppointmentStatus::Confirmed->value], true) ? 'paid' : 'unpaid',
                    'customer_notes' => 'Seeded appointment note.',
                    'cancel_token' => Str::uuid()->toString(),
                    'reschedule_token' => Str::uuid()->toString(),
                ]
            );

            AppointmentStatusLog::query()->updateOrCreate(
                ['business_id' => $business->id, 'appointment_id' => $appointment->id, 'to_status' => $status],
                ['changed_by' => $business->owner_id, 'from_status' => null, 'note' => 'Seeded status history.']
            );

            return $appointment;
        });
    }

    private function seedInvoices(Business $business, $appointments, $services, $customers)
    {
        return $appointments->take(3)->map(function (Appointment $appointment, int $index) use ($business) {
            $status = $index === 0 ? InvoiceStatus::Paid->value : ($index === 1 ? InvoiceStatus::Partial->value : InvoiceStatus::Unpaid->value);
            $paid = $status === InvoiceStatus::Paid->value ? $appointment->price : ($status === InvoiceStatus::Partial->value ? $appointment->price / 2 : 0);

            $invoice = Invoice::query()->updateOrCreate(
                ['business_id' => $business->id, 'invoice_number' => 'INV-'.str_pad((string) ($index + 1001), 4, '0', STR_PAD_LEFT)],
                [
                    'customer_id' => $appointment->customer_id,
                    'appointment_id' => $appointment->id,
                    'status' => $status,
                    'issue_date' => now()->subDays(7 - $index)->toDateString(),
                    'due_date' => now()->addDays(7 + $index)->toDateString(),
                    'subtotal' => $appointment->price,
                    'discount_total' => 0,
                    'tax_total' => round($appointment->price * 0.08, 2),
                    'total' => round($appointment->price * 1.08, 2),
                    'paid_total' => $paid,
                    'balance_due' => round(($appointment->price * 1.08) - $paid, 2),
                    'currency' => $business->currency,
                    'footer_note' => 'Thank you for choosing '.$business->name.'.',
                ]
            );

            InvoiceItem::query()->updateOrCreate(
                ['business_id' => $business->id, 'invoice_id' => $invoice->id, 'service_id' => $appointment->service_id],
                [
                    'description' => $appointment->service?->name ?? 'Service appointment',
                    'quantity' => 1,
                    'unit_price' => $appointment->price,
                    'tax_rate' => 8,
                    'line_total' => round($appointment->price * 1.08, 2),
                ]
            );

            if ($paid > 0) {
                Payment::query()->updateOrCreate(
                    ['business_id' => $business->id, 'transaction_id' => 'pay_'.$invoice->invoice_number],
                    [
                        'invoice_id' => $invoice->id,
                        'customer_id' => $invoice->customer_id,
                        'amount' => $paid,
                        'currency' => $business->currency,
                        'method' => $index === 0 ? 'stripe' : 'cash',
                        'status' => PaymentStatus::Paid->value,
                        'paid_at' => now()->subDays(2),
                        'note' => 'Seeded payment record.',
                    ]
                );
            }

            return $invoice;
        });
    }

    private function seedReminders(Business $business, $appointments, $invoices, $customers): void
    {
        $templates = [
            ['Booking confirmation', 'booking_confirmation', 'email', 'Your booking is confirmed'],
            ['Appointment reminder', 'appointment_reminder', 'whatsapp', null],
            ['Invoice reminder', 'invoice_reminder', 'email', 'Invoice payment reminder'],
        ];

        foreach ($templates as $template) {
            [$name, $type, $channel, $subject] = $template;

            ReminderTemplate::query()->updateOrCreate(
                ['business_id' => $business->id, 'type' => $type, 'channel' => $channel],
                [
                    'name' => $name,
                    'subject' => $subject,
                    'body' => 'Hello {customer_name}, this is a Booklio demo message for {business_name}.',
                    'status' => 'active',
                    'variables' => ['customer_name', 'business_name', 'appointment_date', 'invoice_number'],
                ]
            );
        }

        $appointment = $appointments->first();
        $invoice = $invoices->first();
        $customer = $customers->first();

        $scheduled = ScheduledReminder::query()->updateOrCreate(
            ['business_id' => $business->id, 'type' => 'appointment_reminder', 'recipient' => $customer->phone],
            [
                'customer_id' => $customer->id,
                'appointment_id' => $appointment->id,
                'channel' => 'whatsapp',
                'message' => 'Reminder: your appointment is tomorrow.',
                'scheduled_at' => now()->addDay(),
                'status' => ReminderStatus::Scheduled->value,
            ]
        );

        ReminderLog::query()->updateOrCreate(
            ['business_id' => $business->id, 'scheduled_reminder_id' => $scheduled->id, 'status' => ReminderStatus::Scheduled->value],
            [
                'customer_id' => $customer->id,
                'type' => 'appointment_reminder',
                'channel' => 'whatsapp',
                'recipient' => $customer->phone,
                'message_preview' => 'Reminder: your appointment is tomorrow.',
            ]
        );

        ScheduledReminder::query()->updateOrCreate(
            ['business_id' => $business->id, 'type' => 'invoice_reminder', 'recipient' => $customer->email],
            [
                'customer_id' => $customer->id,
                'invoice_id' => $invoice->id,
                'channel' => 'email',
                'subject' => 'Invoice reminder',
                'message' => 'Please review your invoice.',
                'scheduled_at' => now()->addDays(2),
                'status' => ReminderStatus::Scheduled->value,
            ]
        );
    }

    private function seedSettings(Business $business): void
    {
        $settings = [
            ['booking', 'auto_confirm_bookings', true],
            ['booking', 'slot_interval', 30],
            ['invoice', 'invoice_prefix', 'INV'],
            ['payment', 'default_currency', $business->currency],
            ['notification', 'appointment_reminder_hours', 24],
            ['branding', 'primary_color', '#2563EB'],
            ['localization', 'default_language', 'en'],
        ];

        foreach ($settings as [$group, $name, $value]) {
            Setting::query()->updateOrCreate(
                ['business_id' => $business->id, 'group' => $group, 'name' => $name],
                ['value' => $value, 'is_encrypted' => false]
            );
        }
    }

    private function seedActivityAndSupport(Business $business): void
    {
        ActivityLog::query()->create([
            'business_id' => $business->id,
            'user_id' => $business->owner_id,
            'event' => 'business.seeded',
            'description' => "{$business->name} demo data created.",
            'ip_address' => '127.0.0.1',
            'properties' => ['source' => 'seeder'],
        ]);

        SupportTicket::query()->updateOrCreate(
            ['ticket_number' => 'TCK-'.$business->id.'001'],
            [
                'business_id' => $business->id,
                'user_id' => $business->owner_id,
                'subject' => 'Demo support ticket',
                'status' => SupportTicketStatus::Open->value,
                'priority' => 'normal',
                'category' => 'setup',
                'message' => 'This placeholder ticket verifies the support table and relationships.',
                'last_reply_at' => now()->subHours(4),
            ]
        );
    }
}
