<?php

namespace App\Controllers;

use CodeIgniter\API\ResponseTrait;
use App\Models\SpinRewardModel;
use App\Models\PointsModel;

class SpinWheel extends BaseController
{
    use ResponseTrait;

    private function selectRewardPoints(): int
    {
        $weights = [
            25 => 100,
            50 => 100,
            100 => 50,
            200 => 50,
            250 => 35,
            350 => 35,
            500 => 35,
        ];

        $totalWeight = array_sum($weights);
        $pick = random_int(1, $totalWeight);
        $running = 0;

        foreach ($weights as $points => $weight) {
            $running += $weight;
            if ($pick <= $running) {
                return (int) $points;
            }
        }

        return 25;
    }

    private function normalizeMsisdn(string $msisdn): string
    {
        $msisdn = preg_replace('/[^0-9]/', '', $msisdn);
        if (strlen($msisdn) === 10) {
            $msisdn = '256' . substr($msisdn, 1);
        }

        return $msisdn;
    }

    public function start()
    {
        try {
            $spinDate = date('Y-m-d');
            $points = $this->selectRewardPoints();

            $spinModel = new SpinRewardModel();
            $spinId = $spinModel->insert([
                'points' => $points,
                'spin_date' => $spinDate,
                'created_at' => date('Y-m-d H:i:s'),
            ], true);

            if (!$spinId) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Failed to create spin reward.'
                ], 500);
            }

            return $this->respond([
                'success' => true,
                'spin_id' => (int) $spinId,
                'points' => $points,
            ]);
        } catch (\Throwable $ex) {
            return $this->fail([
                'success' => false,
                'message' => 'Failed to start spin: ' . $ex->getMessage()
            ], 500);
        }
    }

    public function claim()
    {
        try {
            $requestData = $this->request->getJSON(true);
            if (!$requestData || !is_array($requestData)) {
                $requestData = $this->request->getPost();
            }

            $spinId = (int) ($requestData['spin_id'] ?? 0);
            $msisdn = (string) ($requestData['msisdn'] ?? '');

            if ($spinId <= 0 || empty($msisdn)) {
                return $this->fail([
                    'success' => false,
                    'message' => 'spin_id and msisdn are required'
                ], 400);
            }

            $msisdn = $this->normalizeMsisdn($msisdn);
            $spinDate = date('Y-m-d');

            $spinModel = new SpinRewardModel();
            $spin = $spinModel->find($spinId);

            if (!$spin) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Spin reward not found'
                ], 404);
            }

            if (!empty($spin['claimed_at'])) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Spin reward already claimed'
                ], 400);
            }

            if ($spin['spin_date'] !== $spinDate) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Spin reward expired'
                ], 400);
            }

            if ($spinModel->hasClaimedToday($msisdn, $spinDate)) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Already claimed spin reward today'
                ], 400);
            }

            $db = \Config\Database::connect();
            $db->transStart();

            $updated = $spinModel->update($spinId, [
                'msisdn' => $msisdn,
                'claimed_at' => date('Y-m-d H:i:s'),
            ]);

            if (!$updated) {
                $db->transRollback();
                return $this->fail([
                    'success' => false,
                    'message' => 'Failed to claim spin reward'
                ], 500);
            }

            $pointsModel = new PointsModel();
            $awarded = $pointsModel->addPoints($msisdn, (int) $spin['points'], true);

            if (!$awarded) {
                $db->transRollback();
                return $this->fail([
                    'success' => false,
                    'message' => 'Failed to award points'
                ], 500);
            }

            $db->table('points_log')->insert([
                'msisdn' => $msisdn,
                'points' => (int) $spin['points'],
                'reason' => 'Spin Wheel reward',
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            $db->transComplete();

            if ($db->transStatus() === false) {
                return $this->fail([
                    'success' => false,
                    'message' => 'Failed to claim spin reward'
                ], 500);
            }

            return $this->respond([
                'success' => true,
                'points' => (int) $spin['points'],
                'msisdn' => $msisdn,
            ]);
        } catch (\Throwable $ex) {
            return $this->fail([
                'success' => false,
                'message' => 'Failed to claim reward: ' . $ex->getMessage()
            ], 500);
        }
    }
}
