<?php

namespace App\Services;

use App\Jobs\SendTelegramGroupMessageJob;
use App\Models\Config;
use App\Models\PcCao;
use App\Models\PcCaoHistory;
use App\Models\PcIssue;
use App\Models\PcPrediction;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class PcIssueService extends BaseService
{
    public static $MODEL = PcIssue::class;


    public static function index(): void
    {
        //创建新的期号
        PcIssueService::createIssueNo();
        //对该封盘的进行封盘
        PcIssueService:: fengPan();
        //将未开奖的进行开奖
        PcIssueService:: kaiJiang();


    }

    private static function fengPan()
    {
        $list = PcIssue::where('status', PcIssue::STATUS_BETTING)->get();
        $now = time();
        foreach ($list as $item) {
            if (strtotime($item->end_time) - 30 <= $now) {
                $item->status = PcIssue::STATUS_CLOSE;
                $item->save();
            }
        }
    }


    private static function kaiJiang(): void
    {
        $list = PcIssue::where('status', PcIssue::STATUS_CLOSE)->get();
        $now = time();
        foreach ($list as $item) {
            if (strtotime($item->end_time) <= $now) {
                $keno = static::getKeno();
                $item->keno = json_encode($keno);
                $winningNumbers = static::getWinningNumbers($keno);
                $item->winning_numbers = implode(',', $winningNumbers);
                $item->save();


                $winArr = array_map('intval', $winningNumbers);
                // 组合
                $sum = array_sum($winArr);
                $combo = [];
                $sumSize = IssueService::calculateSumSize($sum);  // 总和大小
                $combo[] = $sumSize;

                $sumOddEven = IssueService::calculateOddEven($sum); // 总和单双
                $combo[] = $sumOddEven;
                $sumExtremeSize = IssueService::calculateSumExtremeSize($sum);  // 总和极值
                if ($sumExtremeSize) {
                    $combo[] = $sumExtremeSize;
                }
                $sumBaoZi = IssueService::isBaoZi($winArr[0], $winArr[1], $winArr[2]); // 豹子
                if ($sumBaoZi) {
                    $combo[] = $sumBaoZi;
                }
                $sumPair = IssueService::isPair($winArr[0], $winArr[1], $winArr[2]); // 对子
                if ($sumPair) {
                    $combo[] = $sumPair;
                }
                $sumStraight = IssueService::isStraight($winArr[0], $winArr[1], $winArr[2]); // 顺子
                if ($sumStraight) {
                    $combo[] = $sumStraight;
                }
                $tail = IssueService::getLastDigit($sum); // 总和尾数
                if ($tail != 0 && $tail != 9) {
                    $combo[] = '尾' . $tail; // 尾数
                }


                $key = 'lottery_numbers_' . $item->issue_no;
                $combo = implode(' ', $combo);

                if (Cache::add($key, $item->winning_numbers, 100)) {
                    $res = self::lotteryDraw($item->issue_no, $item->winning_numbers, $combo, '');
//                    'code' => self::NOT
                }


                $awards = IssueService::award(explode(',', $item->winning_numbers));
                //预测结果
                PcPrediction::result($item->issue_no, $item->winning_numbers, $awards);
                //自开奖以来的结果统计
                PcCao::updateData($awards);
                //每天开奖结果统计
                PcCaoHistory::updateData($awards);


            }
        }
    }

    //开奖
    private static function lotteryDraw($issue_no, $winning_numbers, $combo, $recordImage)
    {
        $info = PcIssue::where('issue_no', $issue_no)->first();
        if (!$info) {
            return ['code' => self::NOT, 'msg' => '期号不存在'];
        }
        if ($info->status == PcIssue::STATUS_DRAW) {
            return ['code' => self::NOT, 'msg' => '期号状态不正确'];
        }

        $winArr = array_map('intval', explode(',', $winning_numbers));
        // 计算中奖
        $awards = IssueService::award(explode(',', $winning_numbers));
        DB::beginTransaction();
        try {
            $info->status = PcIssue::STATUS_DRAW;
            $info->combo = $combo;
            $info->image = $recordImage;
            $info->save();


            $replyInfo = KeyboardService::findOne(['button' => '本期开奖']);

            if ($replyInfo) {
                $text = $replyInfo->reply;
                $text .= "\n";
                $text .= $info->issue_no . "： " . implode('+', explode(',', $winning_numbers)) . "=" . array_sum($winArr) . " " . $combo;

                $buttons = json_decode($replyInfo->buttons, true);
                $image = $replyInfo->image;
                if ($image) {
                    $image = url($image);
                }
                if (empty($buttons)) {
                    $serviceAccount = Config::where('field', 'service_account')->first()->val;
                    $buttons[] = [['text' => lang('✅唯一财务'), 'callback_data' => "", 'url' => "https://t.me/{$serviceAccount}"]];

                }
                SendTelegramGroupMessageJob::dispatch($text, $buttons, $image, true);
            }

            if (config('app.url') != 'https://bot28dev.testx2.cc') {
                $recordImage = self::lotteryImage($info->issue_no);
            }
            if ($recordImage) {
                SendTelegramGroupMessageJob::dispatch('', [], url($recordImage), false);
            }
            BetService::betSettled($info->issue_no, $awards);
            DB::commit();
            return ['code' => self::YES, 'msg' => '开奖成功'];
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('开奖失败: ' . $e->getMessage() . $winning_numbers);
            return ['code' => self::NOT, 'msg' => '开奖失败'];
        }
    }


    // 生成开奖图片
    private static function lotteryImage($issue_no)
    {
        $list = PcIssue::where('issue_no', '<=', $issue_no)->where('status', PcIssue::STATUS_DRAW)->orderBy('issue_no', 'desc')->take(20)->get();
        $records = $list->toArray();

        foreach ($records as $k => $v) {
            $winning_numbers = explode(',', $v['winning_numbers']);
            $v['winning_numbers'] = $winning_numbers;

            // 组合
            $sum = array_sum($winning_numbers);

            $v['sum'] = $sum;
            $sumOddEven = IssueService::calculateOddEven($sum); // 总和单双

            $sumSize = IssueService::calculateSumSize($sum);  // 总和大小
            $v['combo'] = $sumSize . ' ' . $sumOddEven;

            $sumExtremeSize = IssueService::calculateSumExtremeSize($sum);  // 总和极值
            if (!$sumExtremeSize) {
                $sumExtremeSize = '-';
            }
            $v['extreme'] = $sumExtremeSize;

            $tail = IssueService::getLastDigit($sum); // 总和尾数
            if ($tail === 0 || $tail === 9) {
                $tailStr = '-';
            } else {
                $tailStr = '尾' . $tail;
            }
            $v['tail'] = $tailStr;

            $records[$k] = $v;
        }
        $service = new LotteryImageService();
        $url = $service->generate($records);

        PcIssue::where('issue_no', $issue_no)->update(['image' => $url]);
        return $url;

    }

    //创建新的一期
    private static function createIssueNo()
    {
        $issue = PcIssue::orderByDesc('id')->first();
        $now = time();
        if (strtotime($issue->end_time) <= $now) {
            $issue_no = $issue->issue_no;
            $number = preg_replace('/\D/', '', $issue_no);
            $number = (int)$number + 1;
            $new_str = "P" . $number;
            $end_time = strtotime($issue->end_time) + 210;
            $status = $end_time - 30 > $now ? PcIssue::STATUS_BETTING : PcIssue::STATUS_CLOSE;
            $issue = PcIssue::create([
                'issue_no' => $new_str,
                'status' => $status,
                'start_time' => $issue->end_time,
                'end_time' => date('Y-m-d H:i:s', $end_time),
            ]);
            $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
            if ($pc28Switch == 1) static::betTing($new_str);
            //预测
            PcPrediction::prediction($new_str);
            if (strtotime($issue->end_time) <= $now) {
                static::createIssueNo();
            }
        }


    }

    //群通知，发送玩法规则和开始下注的通知
    private static function betTing($issue_no): array
    {
        $info = PcIssue::where('issue_no', $issue_no)->first();
        if (!$info) {
            return ['code' => self::NOT, 'msg' => '期号不存在'];
        }

        if (!in_array($info->status, [PcIssue::STATUS_DRAFT, PcIssue::STATUS_BETTING])) {
            return ['code' => self::NOT, 'msg' => '期号状态不正确'];
        }

        $info->status = PcIssue::STATUS_BETTING;
        $info->save();
        $replyInfo = KeyboardService::findOne(['button' => '玩法规则']);
        if ($replyInfo) {
            $text = $replyInfo->reply;
            $buttons = json_decode($replyInfo->buttons, true);
            $image = $replyInfo->image;
            if ($image) {
                $image = url($image);
            }
            if (empty($buttons)) {
                $buttons = self::getOperateButton();
            }
            self::asyncBettingGroupNotice($text, $buttons, $image);
        }

        $replyInfo = KeyboardService::findOne(['button' => '开始下注']);
        if ($replyInfo) {
            $text = $replyInfo->reply;
            $buttons = json_decode($replyInfo->buttons, true);
            $image = $replyInfo->image;
            if ($image) {
                $image = url($image);
            }
            self::asyncBettingGroupNotice($text, $buttons, $image);
        }

        return ['code' => self::YES, 'msg' => '开始下注'];
    }

    //获取随机的20个数字
    private static function getKeno(): array
    {
        $numbers = range(1, 80);
        shuffle($numbers);
        $random_numbers = array_slice($numbers, 0, 20);
        sort($random_numbers);
        return $random_numbers;
    }

    //根据20个数字计算开奖号码
    private static function getWinningNumbers($keno): array
    {
        $winningNumbers = [];
        $sum = $keno[1] + $keno[4] + $keno[7] + $keno[10] + $keno[13] + $keno[16];
        $winningNumbers[0] = $sum % 10;
        $sum = $keno[2] + $keno[5] + $keno[8] + $keno[11] + $keno[14] + $keno[17];
        $winningNumbers[1] = $sum % 10;
        $sum = $keno[3] + $keno[6] + $keno[9] + $keno[12] + $keno[15] + $keno[18];
        $winningNumbers[2] = $sum % 10;
        return $winningNumbers;
    }

    //根据指定0-27的数字 得到20个数字
    public static function getMatchingNumbers($target): array|null
    {
        $numbers = range(1, 80);
        $bestMatch = null;
        for ($i = 0; $i < 100000; $i++) {
            shuffle($numbers);
            $selectedNumbers = array_slice($numbers, 0, 20);
            sort($selectedNumbers);
            $firstSum = $selectedNumbers[1] + $selectedNumbers[4] + $selectedNumbers[7] + $selectedNumbers[10] + $selectedNumbers[13] + $selectedNumbers[16];
            $firstDigit = $firstSum % 10;
            $secondSum = $selectedNumbers[2] + $selectedNumbers[5] + $selectedNumbers[8] + $selectedNumbers[11] + $selectedNumbers[14] + $selectedNumbers[17];
            $secondDigit = $secondSum % 10;
            $thirdSum = $selectedNumbers[3] + $selectedNumbers[6] + $selectedNumbers[9] + $selectedNumbers[12] + $selectedNumbers[15] + $selectedNumbers[18];
            $thirdDigit = $thirdSum % 10;
            $result = $firstDigit + $secondDigit + $thirdDigit;
            if ($result === $target) {
                $bestMatch = $selectedNumbers;
                break;
            }
        }
        return $bestMatch;
    }


}