<?php

namespace App\Controllers;

use App\Models\TipModel;
use App\Models\TipSaleModel;
use App\Models\TipsterWithdrawalModel;
use App\Libraries\MobileMoneyService;

class Tipster extends BaseController
{
    protected $tipModel;
    protected $db;

    public function __construct()
    {
        $this->tipModel = new TipModel();
        $this->db = \Config\Database::connect();
    }

    public function index()
    {
        $tipsterAuthor = session()->get('tipsterAuthor');
        
        // Get tipster stats
        $tipsterStatsModel = new \App\Models\TipsterStatsModel();
        $tipster = $tipsterStatsModel->find($tipsterAuthor);
        $ticketHistory = $tipsterStatsModel->getRecentTicketsWithStats($tipsterAuthor, 5);
        foreach ($ticketHistory as &$ticket) {
            $settled = $ticket['correct'] + $ticket['wrong'];
            $ticket['success_pct'] = $settled > 0
                ? round($ticket['correct'] / $settled * 100, 1)
                : null;
        }
        unset($ticket);
        $latestTickets = $ticketHistory;
        
        // Get recent tips count
        $recentTips = $this->tipModel->where('author', $tipsterAuthor)
            ->where('created_at >=', date('Y-m-d H:i:s', strtotime('-7 days')))
            ->countAllResults();
        
        // Get total tips count
        $totalTips = $this->tipModel->where('author', $tipsterAuthor)->countAllResults();
        
        $data = [
            'tipster' => $tipster,
            'recentTips' => $recentTips,
            'totalTips' => $totalTips,
            'latestTickets' => $latestTickets,
        ];
        
        return view('tipster/dashboard', $data);
    }

    public function addTip()
    {
        $data = [
            'tipModel' => $this->tipModel,
            'nextTipId' => $this->tipModel->getNextId()
        ];
        return view('tipster/add_tip', $data);
    }

    public function saveTip()
    {
        $data = $this->request->getPost();
        $tipsterAuthor = session()->get('tipsterAuthor');

        // Format the matches with all fields
        $matches = [];
        foreach ($data['matches'] as $index => $match) {
            $matches[] = format_tip_match_leg($match);
        }

        // Process booking codes
        $bookingCodes = [];
        if (!empty($data['booking_codes']) && is_array($data['booking_codes'])) {
            foreach ($data['booking_codes'] as $code) {
                if (!empty($code['provider']) && !empty($code['code'])) {
                    $bookingCodes[] = [
                        'provider' => $code['provider'],
                        'code' => $code['code']
                    ];
                }
            }
        }

        // Data to insert into database
        $tip = [
            'title' => $data['title'],
            'tag' => $data['tag'],
            'category' => $data['category'],
            'matches' => json_encode($matches),
            'booking_codes' => json_encode($bookingCodes),
            'amount' => $data['amount'],
            'author' => $tipsterAuthor, // Use logged-in tipster's name
            'odds_source' => $data['odds_source'],
            'match_time' => !empty($data['match_time']) ? date('Y-m-d H:i:s', strtotime($data['match_time'])) : null,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
            'is_hot' => 0, // Tipsters cannot set as hot
            'is_subscriber_only' => 0 // Tipsters cannot set as subscriber only
        ];

        // Insert data into database
        $this->tipModel->insert($tip);

        return redirect()->to('/tipster/my-tips')->with('success', 'Tip added successfully');
    }

    public function myTips()
    {
        $tipsterAuthor = session()->get('tipsterAuthor');
        $tips = $this->tipModel->where('author', $tipsterAuthor)
            ->orderBy('created_at', 'DESC')
            ->findAll();
        
        $data = [
            'tips' => $tips
        ];
        
        return view('tipster/my_tips', $data);
    }

    public function editTip($id)
    {
        $tip = $this->tipModel->find($id);
        $tipsterAuthor = session()->get('tipsterAuthor');

        if (!$tip) {
            return redirect()->to('/tipster/my-tips')->with('error', 'Tip not found');
        }

        // Check if tip belongs to logged-in tipster
        if ($tip['author'] !== $tipsterAuthor) {
            return redirect()->to('/tipster/my-tips')->with('error', 'You can only edit your own tips');
        }

        // Check if match_time has passed
        if (!empty($tip['match_time'])) {
            $matchTime = strtotime($tip['match_time']);
            $now = time();
            if ($matchTime <= $now) {
                return redirect()->to('/tipster/my-tips')->with('error', 'Cannot edit tip after kick-off time');
            }
        }

        // Decode the JSON matches field if it's a string
        if (is_string($tip['matches'])) {
            $tip['matches'] = json_decode($tip['matches'], true);
        }

        // Decode the JSON booking_codes field if it's a string
        if (is_string($tip['booking_codes'])) {
            $tip['booking_codes'] = json_decode($tip['booking_codes'], true);
        } else if ($tip['booking_codes'] === null) {
            $tip['booking_codes'] = [];
        }

        return view('tipster/edit_tip', [
            'tip' => $tip
        ]);
    }

    public function updateTip($id)
    {
        $tip = $this->tipModel->find($id);
        $tipsterAuthor = session()->get('tipsterAuthor');
        $data = $this->request->getPost();

        if (!$tip) {
            return redirect()->to('/tipster/my-tips')->with('error', 'Tip not found');
        }

        // Check if tip belongs to logged-in tipster
        if ($tip['author'] !== $tipsterAuthor) {
            return redirect()->to('/tipster/my-tips')->with('error', 'You can only edit your own tips');
        }

        // Check if match_time has passed
        if (!empty($tip['match_time'])) {
            $matchTime = strtotime($tip['match_time']);
            $now = time();
            if ($matchTime <= $now) {
                return redirect()->to('/tipster/my-tips')->with('error', 'Cannot edit tip after kick-off time');
            }
        }

        // Process matches data with all fields
        $matches = $data['matches'];
        if (is_array($matches)) {
            $processedMatches = [];
            foreach ($matches as $match) {
                $processedMatches[] = format_tip_match_leg($match);
            }
            $matches = json_encode($processedMatches);
        }

        // Process booking codes
        $bookingCodes = [];
        if (!empty($data['booking_codes']) && is_array($data['booking_codes'])) {
            foreach ($data['booking_codes'] as $code) {
                if (!empty($code['provider']) && !empty($code['code'])) {
                    $bookingCodes[] = [
                        'provider' => $code['provider'],
                        'code' => $code['code']
                    ];
                }
            }
        }

        $updateData = [
            'title' => $data['title'],
            'tag' => $data['tag'],
            'category' => $data['category'],
            'matches' => $matches,
            'booking_codes' => json_encode($bookingCodes),
            'amount' => $data['amount'],
            'author' => $tipsterAuthor, // Keep original author
            'odds_source' => $data['odds_source'],
            'match_time' => !empty($data['match_time']) ? date('Y-m-d H:i:s', strtotime($data['match_time'])) : null,
            'updated_at' => date('Y-m-d H:i:s'),
            'is_hot' => 0, // Tipsters cannot set as hot
            'is_subscriber_only' => 0 // Tipsters cannot set as subscriber only
        ];

        $this->tipModel->update($id, $updateData);
        return redirect()->to('/tipster/my-tips')->with('success', 'Tip updated successfully');
    }
    
    /**
     * Display sales/earnings page
     */
    public function sales()
    {
        $tipsterAuthor = session()->get('tipsterAuthor');
        
        if (!$tipsterAuthor) {
            return redirect()->to('/tipster/login')->with('error', 'Please login first');
        }
        
        $tipSaleModel = new TipSaleModel();
        $withdrawalModel = new TipsterWithdrawalModel();
        
        // Get sales summary (last 7 days)
        $sevenDaysAgo = date('Y-m-d H:i:s', strtotime('-7 days'));
        $allSales = $tipSaleModel->where('author', $tipsterAuthor)
                                 ->where('created_at >=', $sevenDaysAgo)
                                 ->findAll();
        
        $settlementSummary = $tipSaleModel->getSettlementSummary($tipsterAuthor, 7);
        
        // Calculate available balance (60% of unsettled sales)
        $availableBalance = $settlementSummary['unsettled_amount'] * 0.6;
        
        // Get withdrawal history
        $withdrawals = $withdrawalModel->getWithdrawalsByAuthor($tipsterAuthor);
        
        $data = [
            'tipsterAuthor' => $tipsterAuthor,
            'sales' => $allSales,
            'settlementSummary' => $settlementSummary,
            'availableBalance' => $availableBalance,
            'withdrawals' => $withdrawals,
        ];
        
        return view('tipster/sales', $data);
    }
    
    /**
     * Validate phone number via AJAX
     */
    public function validatePhone()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Invalid request'
            ]);
        }
        
        $msisdn = $this->request->getPost('msisdn');
        
        if (empty($msisdn)) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Phone number is required'
            ]);
        }
        
        // Ensure phone number has +256 prefix
        if (!str_starts_with($msisdn, '+256')) {
            if (str_starts_with($msisdn, '256')) {
                $msisdn = '+' . $msisdn;
            } else {
                $msisdn = '+256' . $msisdn;
            }
        }
        
        try {
            $mobileMoneyService = new MobileMoneyService();
            $result = $mobileMoneyService->validatePhoneNumber($msisdn);
            
            return $this->response->setJSON([
                'success' => true,
                'message' => $result['message'] ?? 'Phone number validated',
                'customer_name' => $result['customer_name'] ?? '',
                'msisdn' => $result['msisdn'] ?? $msisdn
            ]);
        } catch (\Exception $e) {
            return $this->response->setJSON([
                'success' => false,
                'message' => $e->getMessage()
            ]);
        }
    }
    
    /**
     * Process withdrawal request
     */
    public function withdraw()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Invalid request'
            ]);
        }
        
        $tipsterAuthor = session()->get('tipsterAuthor');
        
        if (!$tipsterAuthor) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Please login first'
            ]);
        }
        
        $msisdn = $this->request->getPost('msisdn');
        $amount = (float) $this->request->getPost('amount');
        $customerName = $this->request->getPost('customer_name');
        
        // Validate inputs
        if (empty($msisdn) || empty($amount)) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Phone number and amount are required'
            ]);
        }
        
        // Minimum withdrawal amount
        if ($amount < 20000) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Minimum withdrawal amount is 20,000 UGX'
            ]);
        }
        
        // Ensure phone number has +256 prefix
        if (!str_starts_with($msisdn, '+256')) {
            if (str_starts_with($msisdn, '256')) {
                $msisdn = '+' . $msisdn;
            } else {
                $msisdn = '+256' . $msisdn;
            }
        }
        
        // Check available balance
        $tipSaleModel = new TipSaleModel();
        $settlementSummary = $tipSaleModel->getSettlementSummary($tipsterAuthor, 7);
        $availableBalance = $settlementSummary['unsettled_amount'] * 0.6;
        
        if ($amount > $availableBalance) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Withdrawal amount exceeds available balance. Available: ' . number_format($availableBalance, 2) . ' UGX'
            ]);
        }
        
        $db = \Config\Database::connect();
        $withdrawalModel = new TipsterWithdrawalModel();
        $mobileMoneyService = new MobileMoneyService();
        
        // Start database transaction
        $db->transStart();
        
        try {
            // Create withdrawal record with pending status
            $withdrawalData = [
                'author' => $tipsterAuthor,
                'msisdn' => $msisdn,
                'amount' => $amount,
                'currency' => 'UGX',
                'status' => 'pending',
                'customer_name' => $customerName ?? null,
            ];
            
            $withdrawalId = $withdrawalModel->insert($withdrawalData);
            
            // Call Mobile Money API to send payment
            $apiResponse = $mobileMoneyService->sendPayment($msisdn, $amount);
            
            // Update withdrawal with success status and internal reference
            $withdrawalModel->update($withdrawalId, [
                'status' => 'success',
                'internal_reference' => $apiResponse['internal_reference'] ?? null
            ]);
            
            // Automatically mark sales as settled
            $this->markSalesAsSettledForWithdrawal($tipsterAuthor, $amount, $apiResponse['internal_reference'] ?? 'N/A');
            
            $db->transComplete();
            
            if ($db->transStatus() === false) {
                throw new \Exception('Database transaction failed');
            }
            
            return $this->response->setJSON([
                'success' => true,
                'message' => $apiResponse['message'] ?? 'Withdrawal processed successfully',
                'internal_reference' => $apiResponse['internal_reference'] ?? null
            ]);
            
        } catch (\Exception $e) {
            $db->transRollback();
            
            // Update withdrawal with failed status
            if (isset($withdrawalId)) {
                $withdrawalModel->updateStatus($withdrawalId, 'failed', $e->getMessage());
            }
            
            log_message('error', 'Withdrawal Error: ' . $e->getMessage());
            
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Withdrawal failed: ' . $e->getMessage()
            ]);
        }
    }
    
    /**
     * Mark sales as settled for withdrawal (helper method)
     * 
     * @param string $author Tipster author name
     * @param float $withdrawalAmount Amount withdrawn (60% share)
     * @param string $internalReference Internal reference from API
     * @return bool Success status
     */
    private function markSalesAsSettledForWithdrawal($author, $withdrawalAmount, $internalReference)
    {
        // Calculate total sale amount needed: withdrawalAmount / 0.6
        $targetSaleAmount = $withdrawalAmount / 0.6;
        
        // Get oldest unsettled sales (FIFO) until total matches
        $tipSaleModel = new TipSaleModel();
        $salesToSettle = $tipSaleModel->getUnsettledSalesForSettlement($author, $targetSaleAmount, 7);
        
        if (empty($salesToSettle)) {
            log_message('warning', "No sales found to settle for withdrawal. Author: {$author}, Amount: {$withdrawalAmount}");
            return false;
        }
        
        // Get sale IDs
        $saleIds = array_column($salesToSettle, 'id');
        
        // Mark those sales as settled
        $settledBy = "Withdrawal: {$internalReference}";
        $settlementNotes = "Automatic settlement via withdrawal";
        
        return $tipSaleModel->markAsSettled($saleIds, $settledBy, $settlementNotes);
    }
}

