<?php

namespace Modules\User\Facades;

use Carbon\Carbon;
use DateTime;
use Exception;
use Illuminate\Support\HigherOrderCollectionProxy;
use Modules\Gout\Models\GoutCase;
use Modules\User\Models\SignConfig;
use Modules\User\Models\SignLog;
use Modules\User\Models\User;

/**
 * 用户签到
 * Class UserSign
 *
 * @package Modules\User\Facades
 */
class UserSign
{

    /**
     * @param  User  $user
     * @return array
     */
    public static function signIn(User $user, $date = ''): array
    {
        try {
            $date = Carbon::parse($date);//签到日期

            $params = SignConfig::getParams();

            if (!isset($params['open'])) {
                throw new Exception('签到功能未开启');
            }

            if (! self::canSign($user, $date)) {
                throw new Exception(self::getNotSignText($user, $date));
            }

            $continue_days = $user->sign->continue_days;
            $counts        = $user->sign->counts;
            if (SignLog::where('user_id', $user->id)
                ->whereDate('date', (clone $date)->subDay()->toDateString())
                ->exists()) {
                $continue_days++;
            } else {
                $continue_days = 1;
            }

            $crystals  = self::getSignCrystal($continue_days);
            $rule_name = $params['rule_name'];
            $str       = "第{$continue_days}天签到";
            if ($crystals > 0) {
                $user->account->rule($rule_name, 0, false, [
                    'frozen_at' => now()->toDateTimeString(),
                    'settle_at' => now()->toDateTimeString(),
                    'remark'    => '第'.$continue_days.'天签到',
                ]);
                $str .= ",获得{$crystals}水滴"."\n";
//                $str .= '第'.$continue_days.'天签到';
            }


            $task_crystals = self::getTaskCrystal($continue_days);
            if ($task_crystals > 0) {
//                $user->account->rule($rule_name, $task_crystals, true, [
//                    'frozen_at' => now()->toDateTimeString(),
//                    'settle_at' => now()->toDateTimeString(),
//                    'remark'    => '连续签到'.$continue_days.'天',
//                ]);
//                $str .= '连续签到'.$continue_days.'天,获得水晶'.$task_crystals;
                $str .= '连续签到'.$continue_days.'天';
            }

            $user->sign->update([
                'continue_days' => $continue_days,
                'counts'        => ++$counts,
                'last_sign_at'  => $date,
            ]);
            SignLog::create([
                'user_id' => $user->id,
                'date'    => $date,
                'type'    => 0,
            ]);

            return [true, $str];
        } catch (Exception $e) {
            return [false, $e->getMessage()];
        }
    }

    /**
     * 返回连续签到额外任务
     *
     * @param  int  $continue_days
     * @return int
     */
    public static function getTaskCrystal(int $continue_days = 1): int
    {
        $tasks = SignConfig::getTasks();
        $task  = $tasks->firstWhere('day', $continue_days);

        return $task['number'] ?? 0;
    }

    public static function getNextTaskCrystal($continue_days = 1)
    {
        $tasks = SignConfig::getTasks();

        return $tasks->where('day', ' > ', $continue_days)
            ->sortBy('day')
            ->first();
    }

    /**
     * 返回签到奖励
     *
     * @param  int  $continue_days
     * @return HigherOrderCollectionProxy|int|mixed
     */
    public static function getSignCrystal(int &$continue_days = 1)
    {
        $params   = SignConfig::getParams();
        $crystals = 0;

        switch ($params['type']) {
            case 'single':
                $crystals = $params['single_number'];
                break;
            case 'continuous':
                $crystals = (int) $params['continuous_base'] + (int) bcmul($continue_days - 1,
                        $params['continuous_incremental'],
                        0);
                break;
            case 'cycle':
                if ($continue_days > $params['cycle_day']) {
                    $continue_days -= $params['cycle_day'];
                }
                $crystals = (int) $params['cycle_base'] + (int) bcmul($continue_days - 1, $params['cycle_incremental'],
                        0);
                break;
        }

        return $crystals;
    }

    /**
     * Notes   : 某一天是否可签到
     *
     * @Date   : 2021/5/28 3:25 下午
     * @Author : <Jason.C>
     * @param  User  $user
     * @param  Carbon  $date
     * @return bool
     */
    public static function canSign(User $user, DateTime $date): bool
    {
        $identityMiddle = $user->identityMiddle()->first();
        $start_at       = $identityMiddle->started_at;
        if (! $start_at) {
            $start_at = $identityMiddle->created_at;
        }

        return $identityMiddle->identity->order > 1 &&
            Carbon::parse($date)->endOfDay()->gt($start_at) &&
            ! $user->IsSign($date) &&
            $date->isToday();
    }

    /**
     * Notes: 是否可以补签
     *
     * @Author: 玄尘
     * @Date: 2022/8/12 8:51
     * @param  User  $user
     * @param  DateTime  $date
     * @return bool
     */
    public static function canReSign(User $user, DateTime $date): bool
    {
        $identityMiddle = $user->identityMiddle()->first();
        $start_at       = $identityMiddle->started_at;
        if (! $start_at) {
            $start_at = $identityMiddle->created_at;
        }

        return ! $user->IsSign($date) &&
            now()->endOfDay()->gt($date) &&
            ! $date->isToday() &&
            Carbon::parse($date)->endOfDay()->gt($start_at);
    }

    /**
     * Notes: 获取不可打卡的信息
     *
     * @Author: 玄尘
     * @Date: 2022/8/10 13:18
     */
    public static function getNotSignText(User $user, DateTime $date)
    {
        $identityMiddle = $user->identityMiddle()->first();
        if (SignLog::where('user_id', $user->id)->whereDate('date', $date)->exists()) {
            return '今日已打卡';
        }

        if ($identityMiddle->identity->order < 2) {
            return '未开通会员';
        }

        $started_at = $identityMiddle->started_at;
        if (! $started_at) {
            $started_at = $identityMiddle->created_at;
        }

        if ($started_at->gt(Carbon::parse($date)->startOfDay())) {
            return '当前时间还未开通会员';
        }


    }

    /**
     * Notes   : 补签
     *
     * @Date   : 2021/5/28 3:15 下午
     * @Author : <Jason.C>
     * @param  User  $user
     * @param  DateTime  $date
     * @return bool
     * @throws Exception
     */
    public static function replenish(User $user, DateTime $date): array
    {
        if (! self::canReSign($user, $date)) {
            throw new Exception(self::getNotSignText($user, $date));
        }
        $params = SignConfig::getParams();

        $continue_days = $user->sign->continue_days;

        $crystals  = self::getSignCrystal($continue_days);
        $rule_name = $params['rule_name'];
        $str       = $date->format('Y-m-d')."号补签";

        if ($crystals > 0) {
            $user->account->rule($rule_name, 0, false, [
                'frozen_at' => now()->toDateTimeString(),
                'settle_at' => now()->toDateTimeString(),
                'remark'    => now()->toDateTimeString().'天补签到',
            ]);
            $str .= ",获得{$crystals}水滴"."\n";
        }

        $counts = $user->sign->counts;


        $user->sign->update([
            'counts' => ++$counts,
        ]);

        $log = SignLog::create([
            'user_id' => $user->id,
            'date'    => $date,
            'type'    => 1,
        ]);

        self::recalculateContinueDays($user);

        return [true, $str];
    }

    /**
     * Notes: 重新计算连续签到日期
     *
     * @Author: 玄尘
     * @Date: 2022/8/4 9:34
     */
    public static function recalculateContinueDays(User $user)
    {
        $reset_at = $user->sign->reset_at;
        $days     = SignLog::query()
            ->byUser($user)
            ->when($reset_at, function ($q) use ($reset_at) {
                $q->where('date', '>=', $reset_at);
            })
            ->latest('date')
            ->pluck('date');

        $continue_days = 1;
        foreach ($days as $key => $day) {
            if (isset($days[$key + 1])) {
                if ($day->subDay()->isSameDay($days[$key + 1])) {
                    $continue_days++;
                } else {
                    break;
                }
            }
        }

        $user->sign->update([
            'continue_days' => max($continue_days, 1),
            'counts'        => $user->signLogs()->count()
        ]);
        return true;
    }

}
