<?php

namespace App\Services;

use App\Models\Market;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class PartnerTokenService
{
    /**
     * Register a new partner
     */
    public function registerPartner(array $data, int $userId): array
    {
        try {
            $partner = DB::transaction(function () use ($data, $userId) {
                // Create partner profile
                $partner = User::create([
                    'name' => $data['name'],
                    'email' => $data['email'],
                    'password' => bcrypt($data['password']), // assuming password is provided
                    'role' => 'partner',
                    'profile' => [
                        'business_description' => $data['business_description'] ?? null,
                        'website' => $data['website'] ?? null,
                        'contact_phone' => $data['contact_phone'] ?? null,
                        'country' => $data['country'] ?? null,
                        'business_type' => $data['business_type'] ?? null,
                        'incorporation_number' => $data['incorporation_number'] ?? null,
                        'status' => 'pending_verification',
                    ],
                ]);

                return $partner;
            });

            return [
                'success' => true,
                'data' => $partner,
                'message' => 'Partner registered successfully'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Submit a token for listing
     */
    public function submitTokenForListing(array $data, int $partnerId): array
    {
        try {
            // Validate required fields
            $requiredFields = ['name', 'symbol', 'total_supply', 'blockchain', 'contract_address', 
                             'description', 'website', 'whitepaper_url', 'listing_fee', 'quote_currency'];
            
            foreach ($requiredFields as $field) {
                if (empty($data[$field])) {
                    throw new \Exception("{$field} is required");
                }
            }

            $token = DB::transaction(function () use ($data, $partnerId) {
                // Create token record
                $token = DB::table('tokens')->insertGetId([
                    'partner_id' => $partnerId,
                    'name' => $data['name'],
                    'symbol' => strtoupper($data['symbol']),
                    'total_supply' => $data['total_supply'],
                    'blockchain' => $data['blockchain'],
                    'contract_address' => $data['contract_address'],
                    'description' => $data['description'],
                    'website' => $data['website'],
                    'whitepaper_url' => $data['whitepaper_url'],
                    'social_media_links' => json_encode($data['social_media_links'] ?? []),
                    'listing_fee' => $data['listing_fee'],
                    'quote_currency' => $data['quote_currency'],
                    'additional_details' => json_encode($data['additional_details'] ?? []),
                    'status' => 'pending_review',
                    'submitted_at' => now(),
                    'updated_at' => now(),
                ]);

                return $token;
            });

            return [
                'success' => true,
                'data' => $token,
                'message' => 'Token submitted for listing successfully'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Approve token listing
     */
    public function approveTokenListing(int $tokenId, int $approverId, array $options = []): array
    {
        try {
            $token = DB::transaction(function () use ($tokenId, $approverId, $options) {
                // Get token details
                $token = DB::table('tokens')->where('id', $tokenId)->first();
                
                if (!$token) {
                    throw new \Exception('Token not found');
                }
                
                if ($token->status !== 'pending_review') {
                    throw new \Exception('Token is not in pending review status');
                }

                // Update token status to approved
                DB::table('tokens')
                  ->where('id', $tokenId)
                  ->update([
                      'status' => 'approved',
                      'approved_at' => now(),
                      'approved_by' => $approverId,
                      'initial_listing_price' => $options['initial_listing_price'] ?? null,
                      'approval_notes' => $options['approval_notes'] ?? null,
                      'updated_at' => now(),
                  ]);

                // Create market for this token
                $marketId = $token->symbol . '-' . $token->quote_currency;
                
                Market::create([
                    'name' => $token->name . '/' . $token->quote_currency,
                    'base_currency' => $token->symbol,
                    'quote_currency' => $token->quote_currency,
                    'status' => 'active',
                    'maker_fee_rate' => $options['maker_fee_rate'] ?? 0.001, // 0.1%
                    'taker_fee_rate' => $options['taker_fee_rate'] ?? 0.002, // 0.2%
                    'min_order_size' => $options['min_order_size'] ?? 0.001,
                    'price_precision' => $options['price_precision'] ?? 8,
                    'quantity_precision' => $options['quantity_precision'] ?? 8,
                    'enabled' => true,
                ]);

                return $token;
            });

            return [
                'success' => true,
                'data' => $token,
                'message' => 'Token approved successfully'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Create a presale event for a token
     */
    public function createPresaleEvent(array $data): array
    {
        try {
            $requiredFields = ['token_id', 'start_time', 'end_time', 'price_per_token', 
                             'soft_cap', 'hard_cap', 'min_purchase', 'max_purchase_per_user'];
            
            foreach ($requiredFields as $field) {
                if (empty($data[$field])) {
                    throw new \Exception("{$field} is required");
                }
            }

            $presale = DB::transaction(function () use ($data) {
                $presaleId = DB::table('presales')->insertGetId([
                    'token_id' => $data['token_id'],
                    'created_by' => $data['created_by'],
                    'start_time' => $data['start_time'],
                    'end_time' => $data['end_time'],
                    'price_per_token' => $data['price_per_token'],
                    'soft_cap' => $data['soft_cap'],
                    'hard_cap' => $data['hard_cap'],
                    'min_purchase' => $data['min_purchase'],
                    'max_purchase_per_user' => $data['max_purchase_per_user'],
                    'additional_terms' => json_encode($data['additional_terms'] ?? []),
                    'status' => 'upcoming',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                return $presaleId;
            });

            return [
                'success' => true,
                'data' => $presale,
                'message' => 'Presale event created successfully'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Participate in a presale
     */
    public function participateInPresale(int $presaleId, int $userId, float $amount): array
    {
        try {
            $result = DB::transaction(function () use ($presaleId, $userId, $amount) {
                // Get presale details
                $presale = DB::table('presales')->where('id', $presaleId)->first();
                
                if (!$presale) {
                    throw new \Exception('Presale not found');
                }
                
                if ($presale->status !== 'active') {
                    throw new \Exception('Presale is not active');
                }
                
                $now = now();
                if ($now->lt($presale->start_time) || $now->gt($presale->end_time)) {
                    throw new \Exception('Presale is not within the valid time window');
                }

                // Check purchase limits
                if ($amount < $presale->min_purchase) {
                    throw new \Exception('Minimum purchase requirement not met');
                }
                
                if ($amount > $presale->max_purchase_per_user) {
                    throw new \Exception('Maximum purchase exceeded');
                }

                // Check if adding this purchase would exceed the hard cap
                $totalRaised = DB::table('presale_purchases')
                                ->where('presale_id', $presaleId)
                                ->sum('amount_paid');
                                
                if ($totalRaised + $amount > $presale->hard_cap) {
                    throw new \Exception('Purchase would exceed hard cap');
                }

                // Verify user has sufficient balance
                $token = DB::table('tokens')->where('id', $presale->token_id)->first();
                $wallet = DB::table('user_wallets')
                           ->where('user_id', $userId)
                           ->where('currency', $token->quote_currency)
                           ->first();
                           
                if (!$wallet || $wallet->available_balance < $amount) {
                    throw new \Exception('Insufficient balance for presale participation');
                }

                // Calculate tokens to be received
                $tokensToReceive = $amount / $presale->price_per_token;

                // Create purchase record
                $purchaseId = DB::table('presale_purchases')->insertGetId([
                    'user_id' => $userId,
                    'presale_id' => $presaleId,
                    'amount_paid' => $amount,
                    'tokens_allocated' => $tokensToReceive,
                    'currency' => $token->quote_currency,
                    'status' => 'pending_allocation',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                // Lock funds for the presale
                // Update wallet balances
                DB::table('user_wallets')
                  ->where('id', $wallet->id)
                  ->decrement('available_balance', $amount);
                  
                DB::table('user_wallets')
                  ->where('id', $wallet->id)
                  ->increment('locked_balance', $amount);

                return [
                    'purchase_id' => $purchaseId,
                    'tokens_allocated' => $tokensToReceive,
                    'amount_paid' => $amount,
                ];
            });

            return [
                'success' => true,
                'data' => $result,
                'message' => 'Successfully participated in presale'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Allocate tokens to presale participants after presale ends
     */
    public function allocatePresaleTokens(int $presaleId): array
    {
        try {
            DB::transaction(function () use ($presaleId) {
                // Get presale details
                $presale = DB::table('presales')->where('id', $presaleId)->first();
                
                if (!$presale) {
                    throw new \Exception('Presale not found');
                }
                
                if ($presale->status !== 'ended') {
                    throw new \Exception('Presale has not ended yet');
                }

                // Get all pending purchases for this presale
                $purchases = DB::table('presale_purchases')
                              ->where('presale_id', $presaleId)
                              ->where('status', 'pending_allocation')
                              ->get();

                foreach ($purchases as $purchase) {
                    // Update purchase status to allocated
                    DB::table('presale_purchases')
                      ->where('id', $purchase->id)
                      ->update([
                          'status' => 'allocated',
                          'allocated_at' => now(),
                          'updated_at' => now(),
                      ]);

                    // Create ledger entry for token allocation
                    $token = DB::table('tokens')->where('id', $presale->token_id)->first();
                    
                    DB::table('ledger_transactions')->insert([
                        'user_id' => $purchase->user_id,
                        'type' => 'presale_allocation',
                        'description' => 'Presale token allocation',
                        'amount' => $purchase->tokens_allocated,
                        'currency' => $token->symbol, // Token symbol as currency
                        'status' => 'completed',
                        'details' => [
                            'presale_id' => $presaleId,
                            'purchase_id' => $purchase->id,
                        ],
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    // Find and update user's wallet for the token
                    $wallet = DB::table('user_wallets')
                               ->where('user_id', $purchase->user_id)
                               ->where('currency', $token->symbol)
                               ->first();
                               
                    if ($wallet) {
                        // Update wallet with allocated tokens
                        DB::table('user_wallets')
                          ->where('id', $wallet->id)
                          ->increment('total_balance', $purchase->tokens_allocated);
                          
                        DB::table('user_wallets')
                          ->where('id', $wallet->id)
                          ->increment('available_balance', $purchase->tokens_allocated);
                    } else {
                        // Create new wallet for this token
                        DB::table('user_wallets')->insert([
                            'user_id' => $purchase->user_id,
                            'currency' => $token->symbol,
                            'total_balance' => $purchase->tokens_allocated,
                            'available_balance' => $purchase->tokens_allocated,
                            'locked_balance' => 0,
                            'settled_balance' => 0,
                            'created_at' => now(),
                            'updated_at' => now(),
                        ]);
                    }

                    // Release the locked funds
                    $quoteCurrencyWallet = DB::table('user_wallets')
                                           ->where('user_id', $purchase->user_id)
                                           ->where('currency', $purchase->currency)
                                           ->first();
                                           
                    if ($quoteCurrencyWallet) {
                        DB::table('user_wallets')
                          ->where('id', $quoteCurrencyWallet->id)
                          ->decrement('locked_balance', $purchase->amount_paid);
                    }
                }
            });

            return [
                'success' => true,
                'message' => 'Presale tokens allocated successfully'
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }
}