<?php

namespace Database\Seeders;

use App\Enums\BillingCycle;
use App\Enums\InvoiceStatus;
use App\Enums\PaymentGateway;
use App\Enums\ProofStatus;
use App\Enums\SubscriptionStatus;
use App\Enums\TenantStatus;
use App\Models\Plan;
use App\Models\SaasProduct;
use App\Models\Subscription;
use App\Models\SubscriptionInvoice;
use App\Models\SubscriptionPayment;
use App\Models\Tenant;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;

/**
 * A believable panel to look at.
 *
 * Run with `php artisan db:seed --class=DemoSeeder`. Deliberately NOT part of
 * DatabaseSeeder: a demo shop appearing in a production dashboard is a support
 * ticket waiting to happen.
 *
 * The data is shaped like a real month rather than uniformly random — most
 * shops are paying quietly, a handful are mid-trial, a few have lapsed, and
 * several payments are sitting in the queue, because an empty queue teaches
 * nobody how the queue works.
 */
class DemoSeeder extends Seeder
{
    public function run(): void
    {
        if (! app()->environment('local', 'development', 'testing')) {
            $this->command->error('DemoSeeder refuses to run outside local/development.');

            return;
        }

        $product = SaasProduct::where('slug', 'thinkrax-pos')->first();

        if (! $product) {
            $this->command->warn('Run the main seeder first.');

            return;
        }

        $plans = Plan::where('saas_product_id', $product->id)->get()->keyBy('slug');

        if ($plans->isEmpty()) {
            $this->command->warn('No plans found — run PlanSeeder first.');

            return;
        }

        $shops = [
            ['Al-Madina Kiryana Store', 'Muhammad Aslam', 'Lahore', 'retail', 'starter'],
            ['Shaheen Traders', 'Bilal Ahmed', 'Faisalabad', 'wholesale', 'business'],
            ['New Karachi Cash & Carry', 'Fahad Siddiqui', 'Karachi', 'retail', 'business'],
            ['Gujranwala Distribution Co.', 'Imran Butt', 'Gujranwala', 'distribution', 'distributor'],
            ['Chishtian Medical Store', 'Dr. Sana Khalid', 'Bahawalpur', 'retail', 'starter'],
            ['Peshawar Mobile Zone', 'Yasir Khan', 'Peshawar', 'retail', 'starter'],
            ['Multan Fabrics House', 'Rehana Bibi', 'Multan', 'retail', 'business'],
            ['Quetta Auto Parts', 'Abdul Samad', 'Quetta', 'wholesale', 'business'],
            ['Sialkot Sports Depot', 'Usman Tariq', 'Sialkot', 'wholesale', 'starter'],
            ['Hyderabad General Store', 'Nadeem Memon', 'Hyderabad', 'retail', 'free-trial'],
            ['Islamabad Stationery Mart', 'Ayesha Malik', 'Islamabad', 'retail', 'free-trial'],
            ['Sargodha Rice Traders', 'Ghulam Mustafa', 'Sargodha', 'distribution', 'distributor'],
        ];

        $created = 0;
        $payments = 0;

        foreach ($shops as $index => [$name, $owner, $city, $type, $planSlug]) {
            $plan = $plans[$planSlug] ?? $plans->first();

            /*
             * Signups are spread backwards over a year so the growth chart has
             * a shape, with the newest shops still inside their trial.
             */
            $joinedDaysAgo = 360 - ($index * 28);

            $tenant = Tenant::updateOrCreate(
                ['slug' => Str::slug($name)],
                [
                    'saas_product_id' => $product->id,
                    'business_name' => $name,
                    'business_type' => $type,
                    'owner_name' => $owner,
                    'owner_email' => Str::slug($owner, '.').'@example.com',
                    'owner_phone' => '03'.str_pad((string) (10000000 + $index * 137171), 9, '0', STR_PAD_LEFT),
                    'country' => 'PK',
                    'city' => $city,
                    'status' => TenantStatus::Active,
                    'trial_ends_at' => now()->copy()->subDays(max(0, $joinedDaysAgo - 14)),
                    'approved_at' => now()->copy()->subDays($joinedDaysAgo),
                    'last_activity_at' => now()->copy()->subHours($index * 3),
                    'created_at' => now()->copy()->subDays($joinedDaysAgo),
                    'referral_source' => ['Facebook', 'Referral', 'Google', 'Walk-in'][$index % 4],
                ],
            );

            $created++;

            $onTrial = $planSlug === 'free-trial';
            $lapsed = $index === 4 || $index === 8;   // two win-back candidates

            $cycle = $index % 3 === 0 ? BillingCycle::Annual : BillingCycle::Monthly;
            $amount = $plan->priceFor($cycle);

            $startsAt = $onTrial
                ? now()->copy()->subDays(5)
                : now()->copy()->subMonths($cycle === BillingCycle::Annual ? 4 : 1);

            $endsAt = $onTrial
                ? now()->copy()->addDays(9)
                : ($lapsed
                    ? now()->copy()->subDays(20)
                    : $startsAt->copy()->addMonths($cycle->months()));

            $tenant->forceFill([
                'status' => match (true) {
                    $onTrial => TenantStatus::Trial,
                    $lapsed => TenantStatus::Expired,
                    default => TenantStatus::Active,
                },
            ])->save();

            $subscription = Subscription::updateOrCreate(
                ['tenant_id' => $tenant->id, 'plan_id' => $plan->id, 'starts_at' => $startsAt],
                [
                    'saas_product_id' => $product->id,
                    'billing_cycle' => $cycle,
                    'status' => match (true) {
                        $onTrial => SubscriptionStatus::Trial,
                        $lapsed => SubscriptionStatus::Expired,
                        default => SubscriptionStatus::Active,
                    },
                    'amount' => $onTrial ? 0 : $amount,
                    'currency' => 'PKR',
                    'ends_at' => $endsAt,
                    'grace_ends_at' => $endsAt->copy()->addDays((int) config('thinkrax.grace_days', 3)),
                    'is_trial' => $onTrial,
                    'auto_renew' => ! $lapsed,
                    'features_snapshot' => $plan->features ?? [],
                    'limits_snapshot' => $plan->limits ?? [],
                ],
            );

            if ($onTrial) {
                continue;
            }

            // A short payment history so the revenue chart is not one bar.
            $terms = $cycle === BillingCycle::Annual ? 1 : 4;

            for ($term = $terms; $term >= 1; $term--) {
                $paidAt = now()->copy()->subMonths($term * $cycle->months());

                if ($paidAt->lt($tenant->created_at)) {
                    continue;
                }

                $invoice = SubscriptionInvoice::create([
                    'tenant_id' => $tenant->id,
                    'subscription_id' => $subscription->id,
                    'invoice_number' => 'TX-'.$paidAt->year.'-'.str_pad((string) (++$payments), 6, '0', STR_PAD_LEFT),
                    'status' => InvoiceStatus::Paid,
                    'subtotal' => $amount,
                    'total' => $amount,
                    'paid_amount' => $amount,
                    'currency' => 'PKR',
                    'issued_on' => $paidAt->toDateString(),
                    'due_on' => $paidAt->copy()->addDays(7)->toDateString(),
                    'period_start' => $paidAt->toDateString(),
                    'period_end' => $paidAt->copy()->addMonths($cycle->months())->toDateString(),
                    'paid_at' => $paidAt,
                ]);

                SubscriptionPayment::create([
                    'tenant_id' => $tenant->id,
                    'subscription_id' => $subscription->id,
                    'subscription_invoice_id' => $invoice->id,
                    'reference' => 'TXP-'.$paidAt->format('Ymd').'-'.strtoupper(Str::random(6)),
                    'gateway' => [PaymentGateway::Easypaisa, PaymentGateway::JazzCash, PaymentGateway::BankTransfer][$index % 3],
                    'amount' => $amount,
                    'currency' => 'PKR',
                    'sender_name' => $owner,
                    'transaction_id' => (string) random_int(100000000, 999999999),
                    'paid_at' => $paidAt,
                    'status' => ProofStatus::Verified,
                    'reviewed_at' => $paidAt->copy()->addHours(2),
                    'created_at' => $paidAt,
                ]);
            }
        }

        $this->seedQueue($product, $plans);

        $this->command->info("Seeded {$created} demo shops with subscriptions, invoices and payment history.");
        $this->command->info('Four payments are waiting in the verification queue.');
    }

    /**
     * Leave a realistic queue behind, including the two cases a reviewer must
     * learn to spot: a short payment, and a duplicated transaction ID.
     */
    protected function seedQueue(SaasProduct $product, $plans): void
    {
        $tenants = Tenant::where('saas_product_id', $product->id)->orderBy('id')->take(4)->get();
        $duplicateTid = (string) random_int(100000000, 999999999);

        foreach ($tenants as $index => $tenant) {
            $subscription = $tenant->currentSubscription();

            if (! $subscription) {
                continue;
            }

            $plan = $plans->firstWhere('id', $subscription->plan_id) ?? $plans->first();
            $due = $plan->priceFor($subscription->billing_cycle);

            $invoice = SubscriptionInvoice::create([
                'tenant_id' => $tenant->id,
                'subscription_id' => $subscription->id,
                'invoice_number' => 'TX-'.now()->year.'-9'.str_pad((string) $index, 5, '0', STR_PAD_LEFT),
                'status' => InvoiceStatus::AwaitingVerification,
                'subtotal' => $due,
                'total' => $due,
                'paid_amount' => 0,
                'currency' => 'PKR',
                'issued_on' => now()->copy()->subDays(2)->toDateString(),
                'due_on' => now()->copy()->addDays(5)->toDateString(),
                'period_start' => now()->toDateString(),
                'period_end' => now()->copy()->addMonths($subscription->billing_cycle->months())->toDateString(),
            ]);

            SubscriptionPayment::create([
                'tenant_id' => $tenant->id,
                'subscription_id' => $subscription->id,
                'subscription_invoice_id' => $invoice->id,
                'reference' => 'TXP-'.now()->format('Ymd').'-'.strtoupper(Str::random(6)),
                'gateway' => [PaymentGateway::Easypaisa, PaymentGateway::JazzCash, PaymentGateway::BankTransfer][$index % 3],
                // The third one is deliberately short, to exercise the warning.
                'amount' => $index === 2 ? round($due * 0.6, 2) : $due,
                'currency' => 'PKR',
                'sender_name' => $tenant->owner_name,
                'sender_account' => $tenant->owner_phone,
                // The last two share a transaction ID, to exercise duplicate detection.
                'transaction_id' => $index >= 2 ? $duplicateTid : (string) random_int(100000000, 999999999),
                'paid_at' => now()->copy()->subHours(6 + $index * 5),
                'tenant_note' => $index === 2 ? 'Baaqi kal bhej dunga, abhi itna hi ho saka.' : null,
                'status' => ProofStatus::Pending,
                'submitted_ip' => '203.0.113.'.(10 + $index),
                'created_at' => now()->copy()->subHours(5 + $index * 4),
            ]);
        }
    }
}
