<?php

namespace Database\Seeders;

use App\Models\Company;
use App\Models\CompanyRegistration;
use App\Models\PortalUser;
use App\Models\User;
use App\Services\NinEncryptionService;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class DemoCompanyRegistrationSeeder extends Seeder
{
    private const TOTAL = 220;

    private const BATCH_SIZE = 50;

    private const PASSWORD = 'admin12342026!!';

    private static array $companyNames = [
        'Nigerian Bottling Company', 'Dangote Industries', 'R and B Foods Limited',
        'Golden Star Trading Company', 'Eko Distribution Services', 'Lagos Ocean Shipping',
        'Kano Textile Mills', 'Abuja Properties Group', 'Rivers Oil Services',
        'Port Harcourt Marine Services', 'Continental Biscuits Nigeria', 'Seven Hills Mining',
        'Tropical Farms Nigeria', 'West African Trade House', 'Federal Logistics Limited',
        'Capital Trust Finance', 'Heritage Insurance Brokers', 'Unity Properties Nigeria',
        'Pan Atlantic Shipping', 'Sunrise Bakeries Nigeria', 'Eagle Wings Aviation',
        'Savannah Telecoms', 'Harmattan Trading Post', 'Delta Oil Field Services',
        'Cross River Exports', 'Anambra Packaging Industries', 'Enugu Mining Corporation',
        'Imo Agro Allied', 'Plateau Mineral Resources', 'Kaduna Textile Works',
        'Kogi Steel Industries', 'Benue Agricultural Produce', 'Nasarawa Stone Quarries',
        'Ogun Industrial Holdings', 'Oyo Properties and Estate', 'Osun Cocoa Export',
        'Ondo Bitumen Resources', 'Ikoyi Capital Partners', 'Victoria Island Trading',
        'Lekki Free Zone Enterprises', 'Apapa Bulk Terminal', 'Tin Can Island Logistics',
        'Alaba Electronics Depot', 'Idumota Commerce Limited', 'Balogun Trading Company',
        'Berger Industries Nigeria', 'Nigerian Paper Mill', 'Nigerian Wire Industries',
        'Ibadan Textile Industries', 'Warri Refinery Services', 'Eleme Petrochemicals',
        'National Salt Company Nigeria', 'National Fertilizer Company', 'Universal Insurance Nigeria',
        'Mutual Benefits Assurance', 'Law Union and Rock Insurance', 'Leadway Assurance Nigeria',
        'AIICO Insurance', 'International Energy Insurance', 'Niger Insurance',
        'Cedar Retail Stores', 'Artee Industries Nigeria', 'Eko Atlantic Properties',
        'Transcorp Hotels Nigeria', 'Federal Palace Hotel Group', 'Continental Hotel Nigeria',
        'Globacom Networks Nigeria', 'Conoil Producing Limited', 'Seplat Energy Nigeria',
        'Ardova Petroleum Nigeria', 'Forte Oil Nigeria', 'Oando Energy Resources',
        'Sahara Energy Resources', 'BUA Group Nigeria', 'Honeywell Group Nigeria',
        'Flour Mills of Nigeria', 'Dufil Prima Foods', 'Chi Limited Nigeria',
        'PZ Cussons Nigeria', 'Evans Medical Nigeria', 'May and Baker Nigeria',
        'Emzor Pharmaceuticals', 'Fidson Healthcare Nigeria', 'Greenfield Pharmaceutical',
        'Strides Healthcare Nigeria', 'Seven-Up Bottling Company', 'International Breweries',
        'Golden Guinea Breweries', 'Notore Chemical Industries', 'BUA Foods Nigeria',
        'Okomu Oil Palm Company', 'Presco Nigeria', 'Vitafoam Nigeria',
        'Lafarge Africa', 'Cement Company of Northern Nigeria', 'Julius Berger Nigeria',
        'Stallion Group Nigeria', 'UAC of Nigeria', 'Nestle Nigeria',
        'Guinness Nigeria', 'Nigerian Breweries', 'Cadbury Nigeria', 'Unilever Nigeria',
    ];

    private static array $directorFirstNames = [
        'Emeka', 'Tunde', 'Femi', 'Chidi', 'Ikenna', 'Nnamdi', 'Uche', 'Rotimi',
        'Biodun', 'Gbenga', 'Yemi', 'Dele', 'Kunle', 'Segun', 'Wale', 'Tunji',
        'Kayode', 'Babajide', 'Olumide', 'Adewale', 'Chinedu', 'Ebuka', 'Ifeanyi',
        'Kingsley', 'Emmanuel', 'Victor', 'Samuel', 'Joseph', 'Ovie', 'Eghosa',
        'Ngozi', 'Chidinma', 'Adaeze', 'Amaka', 'Funke', 'Folake', 'Adeola',
        'Chioma', 'Uchenna', 'Ifeoma', 'Ada', 'Nneka', 'Blessing', 'Grace',
        'Temitope', 'Abimbola', 'Omotola', 'Halima', 'Aisha', 'Fatima',
    ];

    private static array $surnames = [
        'Okafor', 'Adeyemi', 'Nwosu', 'Okonkwo', 'Adesanya', 'Eze', 'Adebayo',
        'Obi', 'Chukwu', 'Adeleke', 'Nwachukwu', 'Abubakar', 'Musa', 'Yusuf',
        'Ibrahim', 'Salami', 'Okoro', 'Igwe', 'Udeh', 'Effiong', 'Akpan',
        'Bassey', 'Udo', 'Nwankwo', 'Kanu', 'Emenike', 'Balogun', 'Afolabi',
        'Abayomi', 'Adekunle', 'Olawale', 'Adeniyi', 'Adenuga', 'Peterside',
        'Mbanefo', 'Lalong', 'Wike', 'Amaechi', 'Obaseki', 'Ugwuanyi',
        'Umahi', 'Soludo', 'Makinde', 'Mohammed', 'Abdullahi', 'Tambuwal',
        'Dangote', 'Otedola', 'Lawson', 'Aliyu',
    ];

    private static array $states = [
        'Lagos', 'Abuja', 'Kano', 'Rivers', 'Oyo', 'Kaduna', 'Enugu', 'Delta',
        'Anambra', 'Imo', 'Ogun', 'Kwara', 'Plateau', 'Cross River', 'Edo',
        'Benue', 'Abia', 'Akwa Ibom', 'Bauchi', 'Borno',
    ];

    private static array $cities = [
        'Lagos', 'Ikeja', 'Abuja', 'Kano', 'Ibadan', 'Port Harcourt', 'Benin City',
        'Maiduguri', 'Zaria', 'Aba', 'Jos', 'Ilorin', 'Oyo', 'Enugu', 'Abeokuta',
        'Onitsha', 'Warri', 'Sokoto', 'Calabar', 'Uyo', 'Kaduna', 'Owerri',
        'Akure', 'Bauchi', 'Minna', 'Katsina', 'Ado-Ekiti', 'Umuahia', 'Osogbo',
        'Yenagoa', 'Asaba', 'Awka', 'Lafia', 'Lokoja', 'Makurdi', 'Gombe', 'Yola',
    ];

    private static array $streets = [
        'Ahmadu Bello Way', 'Herbert Macaulay Street', 'Broad Street', 'Marina',
        'Awolowo Road', 'Adeola Odeku Street', 'Ozumba Mbadiwe Avenue',
        'Bode Thomas Street', 'Allen Avenue', 'Obafemi Awolowo Way',
        'Nnamdi Azikiwe Avenue', 'Yakubu Gowon Way', 'Adetokunbo Ademola Street',
        'Ribadu Road', 'Mobolaji Johnson Avenue', 'Akin Adesola Street',
        'Ligali Ayorinde Street', 'Karimu Kotun Street', 'Kofo Abayomi Street',
    ];

    private static array $areas = [
        'Victoria Island', 'Lekki Phase 1', 'Ikoyi', 'Surulere', 'Ikeja',
        'Yaba', 'Apapa', 'Gbagada', 'Maryland', 'Ojodu', 'Agege', 'Festac Town',
        'Ajah', 'Sangotedo', 'Magodo', 'Oregun', 'Isolo', 'Oshodi', 'Ketu',
    ];

    private static array $statusOptions = [
        ['status' => 'pending_approval', 'account_status' => 'pending', 'verification_status' => 'not_verified', 'weight' => 30],
        ['status' => 'approved',         'account_status' => 'invited', 'verification_status' => 'not_verified', 'weight' => 30],
        ['status' => 'approved',         'account_status' => 'active',  'verification_status' => 'not_verified', 'weight' => 20],
        ['status' => 'rejected',         'account_status' => 'pending', 'verification_status' => 'not_verified', 'weight' => 20],
    ];

    private static array $rejectionReasons = [
        'Incomplete documentation provided.',
        'CAC document could not be verified.',
        'Director identity information is inconsistent.',
        'Provided RC number does not match CAC records.',
        'Suspicious activity detected during review.',
        'Company address could not be verified.',
        'Director NIN does not match provided identity details.',
    ];

    public function run(): void
    {
        $nin     = app(NinEncryptionService::class);
        $adminId = User::where('email', 'admin@josbiz.com')->value('id');

        $bulkStart = Carbon::create(2024, 7, 14);
        $bulkEnd   = Carbon::create(2026, 2, 28);

        $records = [];

        for ($i = 0; $i < self::TOTAL; $i++) {
            $date   = $i < 14
                ? Carbon::create(2026, 3, $i + 1)
                : Carbon::createFromTimestamp(mt_rand($bulkStart->timestamp, $bulkEnd->timestamp));

            $option  = $this->pickWeighted(self::$statusOptions);
            $status  = $option['status'];
            $ninEnc  = $nin->encrypt($this->fakeNin());
            $bvnEnc  = $nin->encrypt($this->fakeBvn());

            $approvedAt = null;
            $rejectedAt = null;
            $approvedBy = null;
            $rejectedBy = null;

            if ($status === 'approved') {
                $approvedBy = $adminId;
                $approvedAt = $date->copy()->addDays(mt_rand(1, 5))->toDateTimeString();
            } elseif ($status === 'rejected') {
                $rejectedBy = $adminId;
                $rejectedAt = $date->copy()->addDays(mt_rand(1, 3))->toDateTimeString();
            }

            $records[] = [
                'index'                             => $i + 1,
                'company_name'                      => $this->pick(self::$companyNames),
                'rc_number'                         => 'RC' . $this->digits(7),
                'country'                           => 'Nigeria',
                'state'                             => $this->pick(self::$states),
                'city'                              => $this->pick(self::$cities),
                'phone_number'                      => '080' . $this->digits(8),
                'secondary_phone'                   => '070' . $this->digits(8),
                'email_address'                     => 'josbizhrintranet+company' . ($i + 1) . '@gmail.com',
                'house_address'                     => $this->address(),
                'previous_address'                  => $this->address(),
                'director_name'                     => $this->pick(self::$directorFirstNames) . ' ' . $this->pick(self::$surnames),
                'director_bvn_encrypted'            => $bvnEnc['iv'] . ':' . $bvnEnc['ciphertext'] . ':' . $bvnEnc['tag'],
                'identity_card_type'                => 'National Identity Number',
                'identity_card_number'              => null,
                'nin_number_encrypted'              => $ninEnc['iv'] . ':' . $ninEnc['ciphertext'] . ':' . $ninEnc['tag'],
                'director_identity_cards_path'      => null,
                'cac_document_path'                 => null,
                'director_passport_photograph_path' => null,
                'consent_given'                     => 1,
                'submission_type'                   => $this->pick(['public_form', 'bulk_upload']),
                'status'                            => $status,
                'account_status'                    => $option['account_status'],
                'verification_status'               => $option['verification_status'],
                'rejection_reason'                  => $status === 'rejected' ? $this->pick(self::$rejectionReasons) : null,
                'company_id'                        => null,
                'submitted_by'                      => null,
                'approved_by'                       => $approvedBy,
                'approved_at'                       => $approvedAt,
                'rejected_by'                       => $rejectedBy,
                'rejected_at'                       => $rejectedAt,
                'created_at'                        => $date->toDateTimeString(),
                'updated_at'                        => $date->toDateTimeString(),
            ];
        }

        shuffle($records);

        $toInsert = array_map(fn ($r) => array_diff_key($r, ['index' => 0]), $records);

        foreach (array_chunk($toInsert, self::BATCH_SIZE) as $chunk) {
            CompanyRegistration::insert($chunk);
        }

        // Create Company record + PortalUser for every approved company registration
        $approved = CompanyRegistration::where('status', 'approved')
            ->where('email_address', 'like', 'josbizhrintranet+company%')
            ->get();

        $now = now()->toDateTimeString();

        foreach ($approved as $reg) {
            $company = Company::firstOrCreate(
                ['email' => $reg->email_address],
                [
                    'name'              => $reg->company_name,
                    'phone'             => $reg->phone_number,
                    'rc_number'         => $reg->rc_number,
                    'address'           => $reg->house_address,
                    'city'              => $reg->city,
                    'state'             => $reg->state,
                    'country'           => 'Nigeria',
                    'insurance_type'    => 'Group Life',
                    'registration_date' => $reg->created_at?->toDateString(),
                    'status'            => 'active',
                ]
            );

            $reg->update(['company_id' => $company->id]);

            PortalUser::firstOrCreate(
                ['email' => $reg->email_address],
                [
                    'company_id'         => $company->id,
                    'name'               => $reg->director_name,
                    'password'           => self::PASSWORD,
                    'role'               => 'company_admin',
                    'two_factor_enabled' => true,
                    'two_factor_setup_at'=> $now,
                    'password_set_at'    => $now,
                    'email_verified_at'  => $now,
                ]
            );
        }
    }

    private function pick(array $items): mixed
    {
        return $items[array_rand($items)];
    }

    private function digits(int $count): string
    {
        $result = '';
        for ($i = 0; $i < $count; $i++) {
            $result .= mt_rand(0, 9);
        }

        return $result;
    }

    private function address(): string
    {
        return mt_rand(1, 120) . ' ' . $this->pick(self::$streets) . ', ' . $this->pick(self::$areas);
    }

    private function pickWeighted(array $options): array
    {
        $total      = array_sum(array_column($options, 'weight'));
        $rand       = mt_rand(1, $total);
        $cumulative = 0;

        foreach ($options as $option) {
            $cumulative += $option['weight'];
            if ($rand <= $cumulative) {
                return $option;
            }
        }

        return $options[array_key_last($options)];
    }

    private function fakeNin(): string
    {
        return sprintf('%011d', mt_rand(10000000000, 99999999999));
    }

    private function fakeBvn(): string
    {
        return sprintf('%011d', mt_rand(10000000000, 99999999999));
    }
}
