<?php

namespace App\Controllers;

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

// CORS headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');

class Predictions extends ResourceController
{
    protected $predictionModel;
    protected $tipsterStatsModel;
    protected $tipModel;
    protected $format = 'json';

    public function __construct()
    {
        $this->predictionModel = new PredictionModel();
        $this->tipsterStatsModel = new TipsterStatsModel();
        $this->tipModel = new TipModel();
    }

    /**
     * Process a tip and extract individual match predictions
     */
    public function processTip($id = null)
    {
        if (!$id) {
            return $this->failValidationErrors('Tip ID is required');
        }

        // Get the tip
        $tip = $this->tipModel->find($id);
        if (!$tip) {
            return $this->failNotFound('Tip not found');
        }

        // Check if matches data exists and is valid
        if (!isset($tip['matches'])) {
            return $this->fail('No matches data found in this tip', 400);
        }

        $matches = json_decode($tip['matches'], true);
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($matches)) {
            return $this->fail('Invalid matches data', 400);
        }

        // Process each match
        $added = 0;
        foreach ($matches as $match) {
            // Check if this match prediction already exists
            $matchData = json_encode($match);
            $existing = $this->predictionModel->where('tip_id', $id)
                ->where('match_data', $matchData)
                ->first();

            // Skip if already processed
            if ($existing) {
                continue;
            }

            // Add new prediction record
            $predictionData = [
                'tip_id' => $id,
                'author' => $tip['author'],
                'match_data' => $matchData,
                'match_date' => date('Y-m-d'), // Set actual match date if available
                'prediction_outcome' => 'pending'
            ];

            $this->predictionModel->insert($predictionData);
            $added++;
        }

        return $this->respond([
            'status' => 'success',
            'message' => "$added new predictions extracted from tip #$id"
        ]);
    }

    /**
     * Mark a prediction as correct or wrong
     */
    /**
     * Mark a prediction as correct or wrong and update scores
     */
    public function updateOutcome($id = null)
    {
        if (!$id) {
            return $this->failValidationErrors('Prediction ID is required');
        }

        $data = $this->request->getJSON(true);
        if (!isset($data['outcome']) || !in_array($data['outcome'], ['correct', 'wrong', 'pending'])) {
            return $this->fail('Valid outcome (correct/wrong/pending) is required', 400);
        }

        // Find the prediction
        $prediction = $this->predictionModel->find($id);
        if (!$prediction) {
            return $this->failNotFound('Prediction not found');
        }

        // Prepare update data
        $updateData = [
            'prediction_outcome' => $data['outcome']
        ];

        // Add scores if provided
        if (isset($data['actual_score'])) {
            $updateData['actual_score'] = $data['actual_score'];
        }
        if (isset($data['ht_score'])) {
            $updateData['ht_score'] = $data['ht_score'];
        }
        if (isset($data['ft_score'])) {
            $updateData['ft_score'] = $data['ft_score'];
        }

        // Update the prediction
        $this->predictionModel->update($id, $updateData);

        // Update author's success rate
        $this->tipsterStatsModel->updateSuccessRate($prediction['author']);

        // Return success message
        return $this->respond([
            'status' => 'success',
            'message' => "Prediction updated successfully",
            'prediction_id' => $id,
            'author' => $prediction['author']
        ]);
    }

    /**
     * Update a prediction's details
     */
    public function update($id = null)
    {
        if (!$id) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction ID is required'
            ]);
        }

        $data = $this->request->getJSON(true);

        // Find the prediction
        $prediction = $this->predictionModel->find($id);
        if (!$prediction) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction not found'
            ]);
        }

        // Validate required fields
        $validation = \Config\Services::validation();
        $validation->setRules([
            'actual_score' => 'required|regex_match[/^\d+-\d+$/]',
            'ht_score' => 'permit_empty|regex_match[/^\d+-\d+$/]',
            'ft_score' => 'permit_empty|regex_match[/^\d+-\d+$/]'
        ]);

        if (!$validation->withRequest($this->request)->run()) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Validation failed',
                'errors' => $validation->getErrors()
            ]);
        }

        // Prepare update data
        $updateData = [
            'actual_score' => $data['actual_score'],
            'ht_score' => $data['ht_score'] ?? null,
            'ft_score' => $data['ft_score'] ?? null
        ];

        // Update the prediction
        if ($this->predictionModel->update($id, $updateData)) {
            return $this->response->setJSON([
                'status' => 'success',
                'message' => 'Score updated successfully',
                'prediction_id' => $id
            ]);
        }

        return $this->response->setJSON([
            'status' => 'error',
            'message' => 'Failed to update score'
        ]);
    }

    /**
     * Get all predictions (with filtering options)
     */
    public function index()
    {
        $filters = $this->request->getGet();

        // Apply filters if any
        $query = $this->predictionModel;

        if (isset($filters['author'])) {
            $query = $query->where('author', $filters['author']);
        }

        if (isset($filters['outcome'])) {
            $query = $query->where('prediction_outcome', $filters['outcome']);
        }

        if (isset($filters['tip_id'])) {
            $query = $query->where('tip_id', $filters['tip_id']);
        }

        // Get paginated results
        $page = isset($filters['page']) ? (int) $filters['page'] : 1;
        $perPage = isset($filters['per_page']) ? (int) $filters['per_page'] : 20;

        $predictions = $query->paginate($perPage, 'default', $page);
        $pager = $query->pager;

        // Process prediction data
        foreach ($predictions as &$prediction) {
            if (isset($prediction['match_data'])) {
                $prediction['match_data'] = json_decode($prediction['match_data'], true);
            }
        }

        return $this->respond([
            'status' => 'success',
            'data' => $predictions,
            'pager' => [
                'current_page' => $pager->getCurrentPage(),
                'per_page' => $perPage,
                'total' => $pager->getTotal(),
                'last_page' => $pager->getPageCount()
            ]
        ]);
    }

    /**
     * Get a single prediction
     */
    public function show($id = null)
    {
        if (!$id) {
            return $this->failValidationErrors('Prediction ID is required');
        }

        $prediction = $this->predictionModel->find($id);

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

        // Decode match data
        if (isset($prediction['match_data'])) {
            $prediction['match_data'] = json_decode($prediction['match_data'], true);
        }

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

    /**
     * Get all tipster stats
     */
    public function getStats()
    {
        $stats = $this->tipsterStatsModel->findAll();

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

    /**
     * Get stats for a specific author
     */
    public function getAuthorStats($author = null)
    {
        if (!$author) {
            return $this->failValidationErrors('Author name is required');
        }

        $author = urldecode($author);

        $stats = $this->tipsterStatsModel->find($author);

        $limit = (int) ($this->request->getGet('limit') ?? 5);
        $limit = max(1, min($limit, 50));
        $ticketHistory = $this->tipsterStatsModel->getRecentTicketsWithStats($author, $limit);
        $yesterdaySuccessRate = $this->calculateYesterdaySuccessRate($author);

        if (!$stats) {
            // Author exists but no stats yet
            return $this->respond([
                'status' => 'success',
                'data' => [
                    'author' => $author,
                    'total_predictions' => 0,
                    'correct_predictions' => 0,
                    'success_rate' => 0,
                    'last_updated' => date('Y-m-d H:i:s'),
                    'ticket_history' => $ticketHistory,
                    'yesterday_success_rate' => $yesterdaySuccessRate
                ]
            ]);
        }

        $stats['ticket_history'] = $ticketHistory;
        $stats['yesterday_success_rate'] = $yesterdaySuccessRate;

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

    /**
     * Calculate yesterday's settled pick success rate for an author.
     */
    private function calculateYesterdaySuccessRate(string $author): float
    {
        $yesterday = date('Y-m-d', strtotime('-1 day'));
        $predictions = $this->predictionModel->where('author', $author)
            ->where('match_date', $yesterday)
            ->whereIn('prediction_outcome', ['correct', 'wrong'])
            ->findAll();

        $correct = 0;
        $wrong = 0;
        foreach ($predictions as $prediction) {
            if ($prediction['prediction_outcome'] === 'correct') {
                $correct++;
            } elseif ($prediction['prediction_outcome'] === 'wrong') {
                $wrong++;
            }
        }

        $total = $correct + $wrong;
        return $total > 0 ? round(($correct / $total) * 100, 2) : 0;
    }

    /**
     * Force recalculation of success rates for all authors
     */
    public function recalculateAll()
    {
        // Get all unique authors
        $authors = $this->predictionModel->select('author')
            ->distinct()
            ->findAll();

        $updated = 0;
        foreach ($authors as $entry) {
            $author = $entry['author'];
            $this->tipsterStatsModel->updateSuccessRate($author);
            $updated++;
        }

        return $this->respond([
            'status' => 'success',
            'message' => "Recalculated success rates for $updated authors"
        ]);
    }

    /**
     * Extract predictions from all tips with a single click
     */
    public function extractAllPredictions()
    {
        try {
            // Get all tips that haven't been processed for predictions yet
            $tips = $this->tipModel->where('is_archived', 0)->findAll();

            $totalProcessed = 0;
            $totalPredictions = 0;

            foreach ($tips as $tip) {
                // Check if matches data exists and is valid
                if (!isset($tip['matches'])) {
                    continue;
                }

                $matches = json_decode($tip['matches'], true);
                if (json_last_error() !== JSON_ERROR_NONE || !is_array($matches)) {
                    continue;
                }

                // Process each match
                $added = 0;
                foreach ($matches as $match) {
                    // Check if this match prediction already exists
                    $matchData = json_encode($match);
                    $existing = $this->predictionModel->where('tip_id', $tip['id'])
                        ->where('match_data', $matchData)
                        ->first();

                    // Skip if already processed
                    if ($existing) {
                        continue;
                    }

                    // Add new prediction record
                    $predictionData = [
                        'tip_id' => $tip['id'],
                        'author' => $tip['author'],
                        'match_data' => $matchData,
                        'match_date' => date('Y-m-d'), // Set actual match date if available
                        'prediction_outcome' => 'pending'
                    ];

                    $this->predictionModel->insert($predictionData);
                    $added++;
                }

                if ($added > 0) {
                    $totalProcessed++;
                    $totalPredictions += $added;
                }
            }

            return $this->response->setJSON([
                'status' => 'success',
                'message' => "Extracted $totalPredictions predictions from $totalProcessed tips",
                'data' => [
                    'tips_processed' => $totalProcessed,
                    'predictions_extracted' => $totalPredictions
                ]
            ]);

        } catch (\Exception $e) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Failed to extract predictions: ' . $e->getMessage()
            ]);
        }
    }

    /**
     * Process all tips and extract individual match predictions
     */
    public function processAllTips()
    {
        try {
            // Get all tips that haven't been processed for predictions yet
            $tips = $this->tipModel->where('is_archived', 0)->findAll();

            $totalProcessed = 0;
            $totalPredictions = 0;

            foreach ($tips as $tip) {
                // Check if matches data exists and is valid
                if (!isset($tip['matches'])) {
                    continue;
                }

                $matches = json_decode($tip['matches'], true);
                if (json_last_error() !== JSON_ERROR_NONE || !is_array($matches)) {
                    continue;
                }

                // Process each match
                $added = 0;
                foreach ($matches as $match) {
                    // Check if this match prediction already exists
                    $matchData = json_encode($match);
                    $existing = $this->predictionModel->where('tip_id', $tip['id'])
                        ->where('match_data', $matchData)
                        ->first();

                    // Skip if already processed
                    if ($existing) {
                        continue;
                    }

                    // Add new prediction record
                    $predictionData = [
                        'tip_id' => $tip['id'],
                        'author' => $tip['author'],
                        'match_data' => $matchData,
                        'match_date' => date('Y-m-d'), // Set actual match date if available
                        'prediction_outcome' => 'pending'
                    ];

                    $this->predictionModel->insert($predictionData);
                    $added++;
                }

                if ($added > 0) {
                    $totalProcessed++;
                    $totalPredictions += $added;
                }
            }

            return $this->response->setJSON([
                'status' => 'success',
                'message' => "Extracted $totalPredictions predictions from $totalProcessed tips",
                'data' => [
                    'tips_processed' => $totalProcessed,
                    'predictions_extracted' => $totalPredictions
                ]
            ]);

        } catch (\Exception $e) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Failed to extract predictions: ' . $e->getMessage()
            ]);
        }
    }

    public function getTipsterHistory($author = null)
    {
        if (!$author) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Author name is required'
            ]);
        }

        $tipsterStatsModel = new \App\Models\TipsterStatsModel();
        $ticketHistory = $tipsterStatsModel->getRecentTicketsWithStats($author);

        return $this->response->setJSON([
            'status' => 'success',
            'data' => [
                'author' => $author,
                'ticket_history' => $ticketHistory
            ]
        ]);
    }

    /**
     * Get overall success rate for all authors for yesterday
     */
    public function getYesterdaySuccessRate()
    {
        $predictionModel = new \App\Models\PredictionModel();
        $yesterday = date('Y-m-d', strtotime('-1 day'));
        $predictions = $predictionModel
            ->where('match_date', $yesterday)
            ->whereIn('prediction_outcome', ['correct', 'wrong'])
            ->findAll();

        $correct = 0;
        $wrong = 0;
        foreach ($predictions as $prediction) {
            if ($prediction['prediction_outcome'] === 'correct') {
                $correct++;
            } elseif ($prediction['prediction_outcome'] === 'wrong') {
                $wrong++;
            }
        }
        $total = $correct + $wrong;
        $yesterdaySuccessRate = $total > 0 ? round(($correct / $total) * 100, 2) : 0;
        return $this->respond([
            'status' => 'success',
            'yesterday_success_rate' => $yesterdaySuccessRate,
            'correct' => $correct,
            'wrong' => $wrong,
            'total' => $total
        ]);
    }

    /**
     * Update prediction scores and outcomes
     */
    public function updateScore($id = null)
    {
        if (!$id) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction ID is required'
            ]);
        }

        $data = $this->request->getJSON(true);

        // Find the prediction
        $prediction = $this->predictionModel->find($id);
        if (!$prediction) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction not found'
            ]);
        }

        // Validate required fields
        $validation = \Config\Services::validation();
        $validation->setRules([
            'prediction_outcome' => 'required|in_list[correct,wrong]',
            'actual_score' => 'required|regex_match[/^\d+-\d+$/]',
            'ht_score' => 'permit_empty|regex_match[/^\d+-\d+$/]',
            'ft_score' => 'permit_empty|regex_match[/^\d+-\d+$/]'
        ]);

        // Validate the JSON data
        if (!$validation->run($data)) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Validation failed',
                'errors' => $validation->getErrors()
            ]);
        }

        // Prepare update data
        $updateData = [
            'prediction_outcome' => $data['prediction_outcome'],
            'actual_score' => $data['actual_score'],
            'ht_score' => $data['ht_score'] ?? null,
            'ft_score' => $data['ft_score'] ?? null,
            'updated_at' => date('Y-m-d H:i:s')
        ];

        // Update the prediction
        if ($this->predictionModel->update($id, $updateData)) {
            // Update author's success rate since outcome changed
            $this->tipsterStatsModel->updateSuccessRate($prediction['author']);
            
            return $this->response->setJSON([
                'status' => 'success',
                'message' => 'Prediction updated successfully',
                'prediction_id' => $id
            ]);
        }

        return $this->response->setJSON([
            'status' => 'error',
            'message' => 'Failed to update prediction'
        ]);
    }

    /**
     * Update a prediction with full details including match_data
     * POST /api/predictions/update-full/{id}
     */
    public function updateFull($id = null)
    {
        if (!$id) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction ID is required'
            ]);
        }

        $data = $this->request->getJSON(true);

        // Find the prediction
        $prediction = $this->predictionModel->find($id);
        if (!$prediction) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Prediction not found'
            ]);
        }

        // Validate required fields
        $validation = \Config\Services::validation();
        $validation->setRules([
            'match_data' => 'required',
            'match_data.team1' => 'required',
            'match_data.team2' => 'required',
            'match_data.prediction' => 'required',
            'match_data.odds' => 'required',
            'match_date' => 'required|valid_date',
            'prediction_outcome' => 'required|in_list[pending,correct,wrong]',
            'actual_score' => 'permit_empty|regex_match[/^\d+-\d+$/]',
            'ht_score' => 'permit_empty|regex_match[/^\d+-\d+$/]',
            'ft_score' => 'permit_empty|regex_match[/^\d+-\d+$/]'
        ]);

        // Validate the JSON data
        if (!$validation->run($data)) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Validation failed',
                'errors' => $validation->getErrors()
            ]);
        }

        // If outcome is not pending, actual_score is required
        if ($data['prediction_outcome'] !== 'pending' && empty($data['actual_score'])) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Final score is required when outcome is not pending'
            ]);
        }

        // Prepare match_data JSON
        $matchData = json_encode($data['match_data']);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Invalid match_data format'
            ]);
        }

        // Prepare update data
        $updateData = [
            'match_data' => $matchData,
            'match_date' => $data['match_date'],
            'prediction_outcome' => $data['prediction_outcome'],
            'actual_score' => $data['actual_score'] ?? null,
            'ht_score' => $data['ht_score'] ?? null,
            'ft_score' => $data['ft_score'] ?? null,
            'updated_at' => date('Y-m-d H:i:s')
        ];

        // Update the prediction
        if ($this->predictionModel->update($id, $updateData)) {
            // Update author's success rate
            $this->tipsterStatsModel->updateSuccessRate($prediction['author']);
            
            return $this->response->setJSON([
                'status' => 'success',
                'message' => 'Prediction updated successfully',
                'prediction_id' => $id
            ]);
        }

        return $this->response->setJSON([
            'status' => 'error',
            'message' => 'Failed to update prediction'
        ]);
    }
}