<?php

namespace App\Jobs;

use App\Model\Master\Client;
use App\Model\Master\ClientServers;
use App\Model\MysqlConnections;
use App\Model\User;
use App\Services\ClientService;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use App\Model\Client\ExtensionGroup;
use App\Model\Extension;
use App\Model\Master\ClientPackage;
use App\Services\PackageService;

class CreateClientJob extends Job
{
    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 5;

    private $client;

    private $asteriskServers = [];

    /**
     * Create a new job instance.
     * @param Client $client
     * @param array $asteriskServers
     * @return void
     */
    public function __construct(Client $client, array $asteriskServers)
    {
        $this->client = $client;
        $this->asteriskServers = $asteriskServers;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Log::info("CreateClientJob.handle", [
            "client" => $this->client,
            "asteriskServers" => $this->asteriskServers
        ]);

        #make entry in mysql_connection table for this user
        if ($this->client->stage < Client::SAVE_CONNECTION) {
            $dbConnection = new MysqlConnections();
            $dbConnection->client_id = $this->client->id;
            $dbConnection->db_name = "client_" . $this->client->id;
            $dbConnection->db_user = env("NEW_CLIENT_USERNAME");
            $dbConnection->password = env("NEW_CLIENT_PASSWORD");
            $dbConnection->ip = env("NEW_CLIENT_HOST");
            $dbConnection->saveOrFail();

            $this->client->stage = Client::SAVE_CONNECTION;
            $this->client->saveOrFail();
        }

        #Create db, grant permissions and Import schema
        if ($this->client->stage < Client::MIGRATE_SEED) {
            Artisan::call('migrate:all');
            Artisan::call('db:seed', ['--class' => 'Database\\Seed\\NotificationSeeder']);
            //Artisan::call('db:seed', ['--class' => 'Database\\Seed\\CrmLabels']);
            Artisan::call('db:seed', ['--class' => 'Database\\Seed\\LabelTableSeeder']);
            Artisan::call('db:seed', ['--class' => 'Database\\Seed\\DispositionTableSeeder']);
            Artisan::call('db:seed', ['--class' => 'Database\\Seed\\DefaultApiTableSeeder']);
            Artisan::call('db:seed', ['--class' => 'Database\\Seed\\CampaignTypesSeeder']);

            $this->client->stage = Client::MIGRATE_SEED;
            $this->client->saveOrFail();
        }

        // add initail credits to wallet
        $this->initializeWalletForClient();

        // add initial DID to client
        $this->initializeDidForClient();


        if ($this->client->stage < Client::ASSIGN_ASTERISK_SERVER) {
            foreach ($this->asteriskServers as $server) {
                $clientServers = new ClientServers();
                $clientServers->client_id = $this->client->id;
                $clientServers->ip_address = $server;
                $clientServers->saveOrFail();
            }
            $this->client->stage = Client::ASSIGN_ASTERISK_SERVER;
            $this->client->saveOrFail();
        }

        #Assign super admin role to all existing super admins
        foreach (User::getAllSuperAdmins() as $adminId) {
            $user = User::find($adminId);
            if (!empty($user) && $user->is_deleted == 0)
                $user->addPermission($this->client->id, 6); //change role by 5 to 6 for system administrator
        }

        // -------- Prospect-to-Client Logic --------
        $this->convertDummyProspectToClient();
        ClientService::clearCache();
    }

    /**
     * Initialize wallet with $5 and add a transaction if wallet tables exist.
     */
    private function initializeWalletForClient()
    {
        $connection = 'mysql_' . $this->client->id;

        if (
            Schema::connection($connection)->hasTable('wallet') &&
            Schema::connection($connection)->hasTable('wallet_transactions')
        ) {

            Log::info("Wallet tables found for client {$this->client->id}");
            $currency = 'USD';
            $amount = 5.0000;


            // check if already exists
            $wallet = DB::connection($connection)
            ->table('wallet')
            ->where('currency_code', $currency)
            ->first();

            // ---- DO NOT add if already has >= 5 ----
            if ($wallet && (float)$wallet->amount >= $amount) {
                Log::info("Initial credits not added; wallet already has {$wallet->amount} USD.");
                return;
            }

            if ($wallet) {
                $newAmount = (float) $wallet->amount + $amount;
                DB::connection($connection)->table('wallet')
                    ->where('currency_code', $currency)
                    ->update(['amount' => $newAmount]);
            } else {
                DB::connection($connection)->table('wallet')->insert([
                    'currency_code' => $currency,
                    'amount' => $amount
                ]);
            }

            // Add wallet transaction
            DB::connection($connection)->table('wallet_transactions')->insert([
                'currency_code' => $currency,
                'amount' => $amount,
                'transaction_type' => 'credit',
                'transaction_reference' => Str::random(12), // unique reference
                'description' => 'Initial trail credits',
                'created_at' => Carbon::now(),
                'updated_at' => Carbon::now()
            ]);

            Log::info("Wallet initialized with $amount USD for client {$this->client->id}");
        } else {
            Log::warning("Wallet tables missing for client {$this->client->id}");
        }
    }

    /**
     * Initialize DID by assigning a reserved CLI from master if DID table exists.
     */
    private function initializeDidForClient()
    {
        $connection = 'mysql_' . $this->client->id;

        if (Schema::connection($connection)->hasTable('did')) {
            Log::info("DID table found for client {$this->client->id}");

            try {
                // Pick the first reserved DID from master
                $masterDid = DB::table('did')
                    ->where('reserved', 1)
                    ->first();

                if (!$masterDid) {
                    Log::warning("No reserved DID found in master for client {$this->client->id}");
                    return;
                }

                // Insert into client DID table with relevant fields
                DB::connection($connection)->table('did')->insert([
                    'cli' => $masterDid->cli,
                    'area_code' => $masterDid->area_code,
                    'country_code' => (int) $masterDid->country_code,
                    'operator' => $masterDid->provider,
                    'voip_provider' => $masterDid->voip_provider,
                ]);

                // Update master to mark as assigned
                DB::table('did')
                    ->where('id', $masterDid->id)
                    ->update([
                        'reserved' => 0,
                        'user_id' => $this->client->id,
                        'parent_id' => (string) $this->client->id,
                    ]);

                Log::info("DID {$masterDid->cli} assigned to client {$this->client->id}");
            } catch (\Exception $e) {
                Log::error("Error assigning DID to client {$this->client->id}: " . $e->getMessage());
            }
        } else {
            Log::warning("DID table missing for client {$this->client->id}");
        }
    }

    private function convertDummyProspectToClient()
    {
        $packageKey = '588703ba-e78a-430f-8872-bb088dc1abba';
        $uniqueSuffix = Str::random(6) . time();
        $asteriskServerId = $this->asteriskServers[0] ?? null;

        $dummyUserData = [
            'first_name' => 'John',
            'last_name' => 'Doe',
            'email' => "john.doe.{$uniqueSuffix}@example.com",
            'password' => Hash::make('123456789'),
            'mobile' => '9' . rand(100000000, 999999999),
            'reserved' => 1,
            'parent_id' => $this->client->id,
            'base_parent_id' => $this->client->id,
        ];

        // Mark client as reserved
        $this->client->reserved = 1;
        $this->client->saveOrFail();

        // Create user
        $user = User::create($dummyUserData);

        // Create default extension group
        $extensionGroup = ExtensionGroup::create([
            'title' => 'default'
        ])->setConnection("mysql_{$this->client->id}");

        // Prepare request for new extension
        $request = new \Illuminate\Http\Request([
            'group_id' => [$extensionGroup->id],
            'first_name' => $dummyUserData['first_name'],
            'last_name' => $dummyUserData['last_name'],
            'email' => $dummyUserData['email'],
            'password' => $dummyUserData['password'],
            'extension' => rand(1001, 9999),
            'alt_extension' => rand(1001, 9999),
            'asterisk_server_id' => $asteriskServerId,
            'mobile' => $dummyUserData['mobile']
        ]);
        $request->auth = (object)['parent_id' => $this->client->id];

        $extensionModel = new Extension();
        $response = $extensionModel->newExtensionSave($request);

        $user->reserved = 1;
        $user->saveOrFail();

        // Assign admin role and switch client
        $user->addPermission($this->client->id, 1);
        $user->switchClient($this->client->id);

        // Assign package
        $clientPackage = ClientPackage::updateOrCreate(
            ['client_id' => $this->client->id, 'package_key' => $packageKey],
            [
                'quantity' => 1,
                'start_time' => Carbon::now(),
                'end_time' => Carbon::now()->addMonth(),
                'expiry_time' => Carbon::now()->addMonth(),
                'billed' => 1,
                'payment_cent_amount' => 5000,
                'payment_time' => Carbon::now(),
                'payment_method' => 'card',
                'psp_reference' => Str::random(12)
            ]
        );

        PackageService::seedUserPackage($clientPackage, [$user->id]);

        Artisan::call('cache:clear');

        Log::info("Dummy prospect converted to client with reserved flag", [
            'email' => $dummyUserData['email'],
            'client_id' => $this->client->id
        ]);
    }
}
