<?php

namespace App\Controllers;

use App\Models\TipModel;
use App\Models\TipsterStatsModel;
use CodeIgniter\RESTful\ResourceController;

// Add this at the beginning of your methods or in a base controller
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');

class Tips extends ResourceController
{
    protected $modelName = 'App\Models\TipModel';
    protected $format = 'json';

    // Create new tip
    public function create()
    {
        $data = $this->request->getJSON(true);

        // Validate required fields
        if (!$data || !isset($data['title'], $data['tag'])) {
            return $this->fail('Missing required fields.', 422);
        }

        // Set default values
        $data['created_at'] = date('Y-m-d H:i:s');
        $data['updated_at'] = date('Y-m-d H:i:s');
        $data['is_hot'] = isset($data['is_hot']) ? (bool) $data['is_hot'] : false; // Ensure boolean
        $data['competition'] = $data['competition'] ?? '';
        $data['is_subscriber_only'] = !empty($data['is_subscriber_only']) ? 1 : 0;

        // Handle matches data
        if (isset($data['matches'])) {
            $data['matches'] = is_array($data['matches'])
                ? json_encode($data['matches'])
                : $data['matches'];
        }

        // Insert and return consistent response
        if ($id = $this->model->insert($data)) {
            // Process the tip predictions automatically
            $predictionController = new Predictions();
            $predictionController->processTip($id);

            return $this->respondCreated([
                'status' => 'success',
                'message' => 'Tip added successfully',
                'data' => [
                    'id' => $id,
                    'title' => $data['title'],
                    'tag' => $data['tag']
                ]
            ]);
        }

        return $this->failServerError('Failed to save tip.');
    }

    // Get all tips
    public function index()
    {
        $tips = $this->model->where('is_archived', 0)->findAll();

        if (empty($tips)) {
            return $this->respond([
                'status' => 'success',
                'data' => []
            ]);
        }

        // Process each tip
        $processedTips = array_map(function ($tip) {
            // Ensure matches is properly decoded
            if (isset($tip['matches'])) {
                $tip['matches'] = json_decode($tip['matches'], true) ?? $tip['matches'];
            }
            return $tip;
        }, $tips);

        return $this->respond([
            'status' => 'success',
            'data' => $processedTips
        ]);
    }

    // Get single tip by ID
    public function show($id = null)
    {
        $tip = $this->model->where('is_archived', 0)->find($id);

        if (!$tip) {
            return $this->failNotFound('Tip not found');
        }

        $db = \Config\Database::connect();
        $tipHitModel = new \App\Models\TipHitModel();
        $db->transStart();

        // Global daily hits (tip_id IS NULL)
        $global = $db->table('tip_hits')->where('tip_id IS NULL', null, false)->get()->getRowArray();
        if ($global) {
            $db->table('tip_hits')->where('id', $global['id'])->update([
                'daily_hits' => $global['daily_hits'] + 1,
                'last_accessed' => date('Y-m-d H:i:s')
            ]);
        } else {
            $db->table('tip_hits')->insert([
                'tip_id' => null,
                'daily_hits' => 1,
                'last_accessed' => date('Y-m-d H:i:s')
            ]);
        }

        // Tip-specific daily hits
        $existing = $tipHitModel->where('tip_id', $id)->first();
        if ($existing) {
            $tipHitModel->update($existing['id'], [
                'daily_hits' => $existing['daily_hits'] + 1,
                'last_accessed' => date('Y-m-d H:i:s')
            ]);
            $tip['hit_count'] = $existing['daily_hits'] + 1;
        } else {
            $tipHitModel->insert([
                'tip_id' => $id,
                'daily_hits' => 1,
                'last_accessed' => date('Y-m-d H:i:s')
            ]);
            $tip['hit_count'] = 1;
        }

        $db->transComplete();

        // Handle matches data - only decode if it's a string
        if (isset($tip['matches'])) {
            if (is_string($tip['matches'])) {
                $decodedMatches = json_decode($tip['matches'], true);
                $tip['matches'] = (json_last_error() === JSON_ERROR_NONE)
                    ? $decodedMatches
                    : ['error' => 'Invalid matches data'];
            } elseif (is_array($tip['matches'])) {
                $tip['matches'] = $tip['matches'];
            } else {
                $tip['matches'] = [];
            }

            if (is_array($tip['matches']) && !isset($tip['matches']['error'])) {
                $tip['matches'] = enrich_match_legs_with_logos($tip['matches']);
            }
        }

        // Handle booking codes data - only decode if it's a string
        if (isset($tip['booking_codes'])) {
            if (is_string($tip['booking_codes'])) {
                $decodedBookingCodes = json_decode($tip['booking_codes'], true);
                $tip['booking_codes'] = (json_last_error() === JSON_ERROR_NONE)
                    ? $decodedBookingCodes
                    : [];
            } elseif (is_array($tip['booking_codes'])) {
                $tip['booking_codes'] = $tip['booking_codes'];
            } else {
                $tip['booking_codes'] = [];
            }
        } else {
            $tip['booking_codes'] = [];
        }

        return $this->respond([
            'status' => 'success',
            'data' => $tip
        ]);
    }

    // Update tip
    public function update($id = null)
    {
        $data = $this->request->getPost();
        $data['id'] = $id;

        // Process matches data
        $matches = [];
        if (!empty($data['matches']) && is_array($data['matches'])) {
            foreach ($data['matches'] as $match) {
                $matches[] = [
                    'team1' => $match['team1'] ?? '',
                    'team2' => $match['team2'] ?? '',
                    'league' => $match['league'] ?? '',
                    'prediction' => $match['prediction'] ?? '',
                    'odds' => $match['odds'] ?? null
                ];
            }
        }
        $data['matches'] = $matches;

        // Handle empty match_time
        if (empty($data['match_time'])) {
            $data['match_time'] = null;
        }

        // Handle checkbox
        $data['is_hot'] = isset($data['is_hot']) ? 1 : 0;

        // Handle is_subscriber_only
        $data['is_subscriber_only'] = !empty($data['is_subscriber_only']) ? 1 : 0;

        // Create update data array with all fields
        $updateData = [
            'title' => $data['title'],
            'tag' => $data['tag'],
            'category' => $data['category'],
            'matches' => $matches,
            'amount' => $data['amount'],
            'author' => $data['author'],
            'odds_source' => $data['odds_source'] ?? null,
            'match_time' => !empty($data['match_time']) ? date('Y-m-d H:i:s', strtotime($data['match_time'])) : null,
            'cta_text' => $data['cta_text'] ?? '',
            'cta_url' => $data['cta_url'] ?? '',
            'partner_logo' => $data['partner_logo'] ?? '',
            'is_hot' => $data['is_hot'],
            'competition' => $data['competition'] ?? '',
            'is_subscriber_only' => $data['is_subscriber_only'],
            'updated_at' => date('Y-m-d H:i:s')
        ];

        // Save data
        if ($this->tipModel->save($updateData)) {
            return redirect()->to('/admin/tips')->with('success', 'Tip saved successfully');
        } else {
            return redirect()->back()
                ->with('errors', $this->tipModel->errors())
                ->withInput();
        }
    }

    public function saveTip()
    {
        $data = $this->request->getPost();

        // Process matches data
        $matches = [];
        if (!empty($data['matches']) && is_array($data['matches'])) {
            foreach ($data['matches'] as $match) {
                $matches[] = [
                    'team1' => $match['team1'] ?? '',
                    'team2' => $match['team2'] ?? '',
                    'league' => $match['league'] ?? '',
                    'prediction' => $match['prediction'] ?? '',
                    'odds' => $match['odds'] ?? null
                ];
            }
        }
        $data['matches'] = $matches;

        // Handle empty match_time
        if (empty($data['match_time'])) {
            $data['match_time'] = null;
        }

        // Handle checkbox
        $data['is_hot'] = isset($data['is_hot']) ? 1 : 0;

        // Handle is_subscriber_only
        $data['is_subscriber_only'] = !empty($data['is_subscriber_only']) ? 1 : 0;

        // Save data
        if ($this->tipModel->save($data)) {
            return redirect()->to('/admin/tips')->with('success', 'Tip saved successfully');
        } else {
            return redirect()->back()
                ->with('errors', $this->tipModel->errors())
                ->withInput();
        }
    }

    // Delete tip
    public function delete($id = null)
    {
        $tip = $this->model->find($id);
        if (!$tip) {
            return $this->failNotFound('Tip not found');
        }

        // Important: The predictions will remain for statistics even after tip deletion
        // Just delete the tip itself
        if ($this->model->delete($id)) {
            return $this->respondDeleted([
                'status' => 'success',
                'message' => 'Tip deleted successfully. Prediction statistics are preserved.'
            ]);
        }

        return $this->failServerError('Failed to delete tip.');
    }

    public function unlock($id = null)
    {
        // Verify tip exists
        $tip = $this->model->find($id);
        if (!$tip) {
            return $this->failNotFound('Tip not found');
        }

        // Check if tip is paid
        if ($tip['tag'] !== 'paid') {
            return $this->fail('This tip is already free', 400);
        }

        // In a real app, you would verify payment here
        // For now, we'll just return success
        return $this->respond([
            'status' => 'success',
            'message' => 'Tip unlocked successfully',
            'data' => [
                'id' => $id,
                'unlocked' => true,
                'matches' => isset($tip['matches']) ? json_decode($tip['matches'], true) : null
            ]
        ]);
    }


    private function checkMatchTime($tipId)
    {
        $tip = $this->model->find($tipId);
        if (!$tip) {
            return [
                'can_purchase' => false,
                'message' => 'Tip not found'
            ];
        }

        // If no match time is set, allow purchase
        if (empty($tip['match_time'])) {
            return [
                'can_purchase' => true,
                'message' => 'No match time restrictions'
            ];
        }

        // Check if any match has started
        $matchTime = strtotime($tip['match_time']);
        $currentTime = time();

        if ($currentTime >= $matchTime) {
            return [
                'can_purchase' => false,
                'message' => 'One or more matches in this tip have already started',
                'match_time' => $tip['match_time']
            ];
        }

        return [
            'can_purchase' => true,
            'message' => 'Matches have not started yet',
            'match_time' => $tip['match_time']
        ];
    }

    public function checkTipAvailability($tipId)
    {
        return $this->respond($this->checkMatchTime($tipId));
    }

    public function purchase()
    {
        $data = $this->request->getJSON(true);

        if (!$data || !isset($data['tip_id'], $data['msisdn'])) {
            return $this->fail('Missing required fields', 400);
        }

        // Check match time before allowing purchase
        $availability = $this->checkMatchTime($data['tip_id']);
        if (!$availability['can_purchase']) {
            return $this->fail($availability['message'], 400);
        }

        // Continue with purchase process...
        // Your existing purchase logic here
    }

    public function getTipsters()
    {
        // Get distinct authors with their stats
        $builder = $this->model->builder();
        $tipsters = $builder
            ->select([
                'author',
                'COUNT(*) as ticket_count',
                'SUM(CASE WHEN tag = "paid" THEN 1 ELSE 0 END) as paid_tickets',
                'SUM(CASE WHEN tag = "free" THEN 1 ELSE 0 END) as free_tickets',
                'MAX(created_at) as last_updated'
            ])
            ->groupBy('author')
            ->orderBy('author', 'ASC')
            ->get()
            ->getResultArray();

        if (empty($tipsters)) {
            return $this->respond([
                'status' => 'success',
                'data' => []
            ]);
        }

        // For each author, calculate success rate (you'll need to join with predictions table)
        // This is a simplified version - you might need to adjust based on your prediction tracking
        $TipsterStatsModel = new TipsterStatsModel();
        foreach ($tipsters as &$tipster) {
            $successRate = $TipsterStatsModel
                ->where('author', $tipster['author'])
                ->selectAvg('success_rate', 'avg_success_rate')
                ->first();

            $tipster['success_rate'] = $successRate['avg_success_rate'] ?? 0;
        }

        return $this->respond([
            'status' => 'success',
            'data' => $tipsters
        ]);
    }

    /**
     * Get tips by specific author
     */
    public function getTipsByAuthor($author = null)
    {
        if (empty($author)) {
            return $this->fail('Author name is required', 400);
        }

        // Decode URL encoded author name
        $author = urldecode($author);

        $tips = $this->model
            ->where('author', $author)
            ->where('is_archived', 0)
            ->orderBy('created_at', 'DESC')
            ->findAll();

        if (empty($tips)) {
            return $this->respond([
                'status' => 'success',
                'data' => []
            ]);
        }

        // Process each tip to a lightweight summary (full details via GET /tips/:id)
        $processedTips = array_map(function ($tip) {
            return $this->summarizeTipForList($tip);
        }, $tips);

        return $this->respond([
            'status' => 'success',
            'data' => $processedTips
        ]);
    }

  /**
     * Strip heavy match payloads from list responses while keeping card metadata.
     */
    private function summarizeTipForList(array $tip): array
    {
        $matches = $tip['matches'] ?? [];
        if (is_string($matches)) {
            $matches = json_decode($matches, true) ?? [];
        }
        if (!is_array($matches)) {
            $matches = [];
        }

        $combinedOdds = 1.0;
        foreach ($matches as $match) {
            if (is_array($match) && isset($match['odds'])) {
                $combinedOdds *= (float) $match['odds'];
            }
        }

        unset($tip['matches'], $tip['booking_codes']);
        $tip['match_count'] = count($matches);
        $tip['combined_odds'] = round($combinedOdds, 2);

        return $tip;
    }

    protected function handleEmptyFields(array $data)
    {
        // Convert empty strings to NULL for nullable fields
        $nullableFields = ['category', 'match_time', 'amount', 'author', 'competition'];

        foreach ($nullableFields as $field) {
            if (isset($data['data'][$field]) && $data['data'][$field] === '') {
                $data['data'][$field] = null;
            }
        }

        // Ensure is_hot is always set as boolean (1 or 0)
        if (isset($data['data']['is_hot'])) {
            $data['data']['is_hot'] = $data['data']['is_hot'] ? 1 : 0;
        } else {
            $data['data']['is_hot'] = 0;
        }

        return $data;
    }

    /**
     * Get tips available for subscribers only
     * GET /tips/subscriber?msisdn=...
     */
    public function subscriberTips()
    {
        $msisdn = $this->request->getGet('msisdn');
        if (!$msisdn) {
            return $this->fail('Phone number (msisdn) is required.', 400);
        }
        $subscriptionModel = new \App\Models\SubscriptionModel();
        $activeSub = $subscriptionModel->isActive($msisdn);
        if (!$activeSub) {
            // Check if user ever had a subscription
            $expiredSub = $subscriptionModel->where('msisdn', $msisdn)->orderBy('end_date', 'DESC')->first();
            if ($expiredSub) {
                return $this->respond([
                    'status' => 'expired',
                    'message' => 'Sorry your subscription has expired, please subscribe a plan to enjoy the services.'
                ], 403);
            }
            return $this->respond([
                'status' => 'not_subscribed',
                'message' => 'Sorry your number does not have an active subscription, Please subscribe to access the services.'
            ], 403);
        }
        $tips = $this->model->where('is_subscriber_only', 1)->where('is_archived', 0)->findAll();
        
        // Remove booking codes from subscription tips to prevent unlimited access
        $processedTips = array_map(function ($tip) {
            $tip['booking_codes'] = null;
            return $tip;
        }, $tips);
        
        return $this->respond([
            'status' => 'success',
            'data' => $this->processTips($processedTips)
        ]);
    }

    /**
     * Get tips available for regular purchase (not subscriber-only)
     * GET /tips/regular
     */
    public function regularTips()
    {
        $tips = $this->model->where('is_subscriber_only', 0)->where('is_archived', 0)->findAll();
        return $this->respond([
            'status' => 'success',
            'data' => $this->processTips($tips)
        ]);
    }

    /**
     * Helper to process tips (decode matches, etc)
     */
    private function processTips($tips)
    {
        return array_map(function ($tip) {
            if (isset($tip['matches'])) {
                $tip['matches'] = is_string($tip['matches']) ? json_decode($tip['matches'], true) : $tip['matches'];
            }
            // Only decode booking codes for non-subscription tips
            if (isset($tip['booking_codes']) && $tip['is_subscriber_only'] == 0) {
                $tip['booking_codes'] = is_string($tip['booking_codes']) ? json_decode($tip['booking_codes'], true) : $tip['booking_codes'];
            } else {
                $tip['booking_codes'] = null;
            }
            return $tip;
        }, $tips);
    }
}