<?php

namespace App\Http\Controllers\Crontab;

use App\Http\Controllers\Controller;
use App\Services\Pair\CheckService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use App\Http\Controllers\Core\Ding;
use App\Models\Fpdx\PairModel;
use App\Models\Fpdx\ActivityModel;
use Ixudra\Curl\Facades\Curl;

class Pair extends Controller
{
    /**
     * 获取当前期数
     * @return mixed
     */
    public function getTodayStageId()
    {
        $stageId = ActivityModel::where(['signend_time' => mktime(12, 0, 0)])->value('stage_id');
        return $stageId;
    }

    /**
     * @param $girl
     * @param $boy
     * @return bool
     * 1 => '年龄必须比我大',
     * 2 => '年龄必须比我小',
     * 3 => '身高必须比我高',
     * 4 => '身高必须比我矮',
     * 5 => '必须是同校',
     * 6 => '必须同城',
     * 7 => '必须是不同校',
     * 8 => '接受同省调剂',
     * 9 => '必须是同乡'
     */
    public function checkLike($girl, $boy)
    {
        if ($girl['pair_province'] == 1 || $boy['pair_province'] == 1) {
            $girl_s = $girl['address'] ? explode('-', trim($girl['address'])) : null;
            $boy_s = $boy['address'] ? explode('-', trim($boy['address'])) : null;
            if (empty($girl_s) || empty($boy_s)) {
                return false;
            } else {
                $boy_s_a = $boy_s[0];
                $girl_s_a = $girl_s[0];
                if (empty($boy_s_a) || empty($girl_s_a)) {
                    return false;
                }
                if ($boy_s_a != $girl_s_a) {
                    return false;
                }
            }
        }
        if (in_array($boy['uid'], $girl['pairs'])) {
            return false;
        }
        if ($girl['sex'] != $boy['sxo'] || $boy['sex'] != $girl['sxo']) {
            return false;
        }
        $boy_age = date('Y') - intval($boy['age']);
        $girl_age = date('Y') - intval($girl['age']);
        //begin
        if (
            ($girl['pair_min_age'] > 9
                || $boy['pair_min_age'] > 9)
            && abs($girl_age - $boy_age) > 4
        ) {
            return false;
        }
        if (
            $boy_age < ($girl_age - $girl['pair_min_age'])
            || $boy_age > ($girl_age + $girl['pair_max_age'])
            || $girl_age < ($boy_age - $boy['pair_min_age'])
            || $girl_age > ($boy_age + $boy['pair_max_age'])
        ) {
            return false;
        }

        if ($girl['sex'] != $boy['sex']) {
            if ($boy['sex'] == 1) { # 男boy女girl
                if ($boy['height'] < ($girl['height'] + 5)) {
                    return false;
                }
            } else { # 男girl女boy
                if ($girl['height'] < ($boy['height'] + 5)) {
                    return false;
                }
            }
        }
        $girl['likes'] = $girl['fpdx_like'] ? explode(',', trim($girl['fpdx_like'], ',')) : [];
        $boy['likes'] = $boy['fpdx_like'] ? explode(',', trim($boy['fpdx_like'], ',')) : [];
        foreach ($girl['likes'] as $girl_like) {
            $self = $girl;
            $other = $boy;
            switch ($girl_like) {
                case 1: // 年龄必须比我大; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 5: // 必须是同校
                    if ($self['school'] != $other['school']) {
                        return false;
                    }
                    break;
                case 6: // 必须同城
                    if ($self['address'] != $other['address']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case 9: // 必须是同乡
                    if ($self['home'] != $other['home']) {
                        return false;
                    }
                    break;
                case -3:
                case -2:
                case -1:
                default:
                    break;
            }
        }
        foreach ($boy['likes'] as $boy_like) {
            $self = $boy;
            $other = $girl;
            switch ($boy_like) {
                case 1: // 年龄必须比我大; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 5: // 必须是同校
                    if ($self['school'] != $other['school']) {
                        return false;
                    }
                    break;
                case 6: // 必须同城
                    if ($self['address'] != $other['address']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case 9: // 必须是同乡
                    if ($self['home'] != $other['home']) {
                        return false;
                    }
                    break;
                case -3:
                case -2:
                case -1:
                default:
                    break;
            }
        }
        return true;
    }

    /**
     *
     * @param $girl
     * @param $boy
     * @return bool
     * 1 => '年龄必须比我大',
     * 2 => '年龄必须比我小',
     * 3 => '身高必须比我高',
     * 4 => '身高必须比我矮',
     * 5 => '必须是同校',
     * 6 => '必须同城',
     * 7 => '必须是不同校',
     * 8 => '接受同省调剂',
     * 9 => '必须是同乡'
     */
    public function checkLike2Sheng($girl, $boy)
    {
        if ($girl['pair_province'] == 0 && $girl['pair_all'] == 0) {
            return false;
        }
        if ($boy['pair_province'] == 0 && $boy['pair_all'] == 0) {
            return false;
        }
        $girl_s = $girl['address'] ? explode('-', trim($girl['address'])) : null;
        $boy_s = $boy['address'] ? explode('-', trim($boy['address'])) : null;
        if (empty($girl_s) || empty($boy_s)) {
            return false;
        } else {
            $boy_s_a = $boy_s[0];
            $girl_s_a = $girl_s[0];
            if (empty($boy_s_a) || empty($girl_s_a)) {
                return false;
            }
            if ($boy_s_a != $girl_s_a) {
                return false;
            }
        }
        if (in_array($boy['uid'], $girl['pairs'])) {
            return false;
        }
        if ($girl['sex'] != $boy['sxo'] || $boy['sex'] != $girl['sxo']) {
            return false;
        }
        $boy_age = date('Y') - intval($boy['age']);
        $girl_age = date('Y') - intval($girl['age']);
        //begin
        if (
            ($girl['pair_min_age'] > 9
                || $boy['pair_min_age'] > 9)
            && abs($girl_age - $boy_age) > 4
        ) {
            return false;
        }

        if (
            $boy_age < ($girl_age - $girl['pair_min_age'])
            || $boy_age > ($girl_age + $girl['pair_max_age'])
            || $girl_age < ($boy_age - $boy['pair_min_age'])
            || $girl_age > ($boy_age + $boy['pair_max_age'])
        ) {
            return false;
        }

        if ($girl['sex'] != $boy['sex']) {
            if ($boy['sex'] == 1) { # 男boy女girl
                if ($boy['height'] < ($girl['height'] + 5)) {
                    return false;
                }
            } else { # 男girl女boy
                if ($girl['height'] < ($boy['height'] + 5)) {
                    return false;
                }
            }
        }
        $girl['likes'] = $girl['fpdx_like'] ? explode(',', trim($girl['fpdx_like'], ',')) : [];
        $boy['likes'] = $boy['fpdx_like'] ? explode(',', trim($boy['fpdx_like'], ',')) : [];
        foreach ($girl['likes'] as $girl_like) {
            $self = $girl;
            $other = $boy;
            switch ($girl_like) {
                case 1: // 年龄必须比我大; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case 8: // 必须同省
                    $girl_s = $girl['address'] ? explode('-', trim($girl['address'])) : null;
                    $boy_s = $boy['address'] ? explode('-', trim($boy['address'])) : null;
                    if (empty($girl_s) || empty($boy_s)) {
                        return false;
                    } else {
                        $boy_s_a = $boy_s[0];
                        $girl_s_a = $girl_s[0];
                        if (empty($boy_s_a) || empty($girl_s_a)) {
                            return false;
                        }
                        if ($boy_s_a != $girl_s_a) {
                            return false;
                        }
                    }
                    break;
                case -2:
                case -3:
                case -1:
                default:
                    break;
            }
        }
        foreach ($boy['likes'] as $boy_like) {
            $self = $boy;
            $other = $girl;
            switch ($boy_like) {
                case 1: // 年龄必须比我大; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case 8: // 必须同省
                    $girl_s = $girl['address'] ? explode('-', trim($girl['address'])) : null;
                    $boy_s = $boy['address'] ? explode('-', trim($boy['address'])) : null;
                    if (empty($girl_s) || empty($boy_s)) {
                        return false;
                    } else {
                        $boy_s_a = $boy_s[0];
                        $girl_s_a = $girl_s[0];
                        if (empty($boy_s_a) || empty($girl_s_a)) {
                            return false;
                        }
                        if ($boy_s_a != $girl_s_a) {
                            return false;
                        }
                    }
                    break;
                case -3:
                case -2:
                case -1:
                default:
                    break;
            }
        }
        return true;
    }

    /**
     * @param $girl
     * @param $boy
     * @return bool
     * 1 => '年龄必须比我大',
     * 2 => '年龄必须比我小',
     * 3 => '身高必须比我高',
     * 4 => '身高必须比我矮',
     * 5 => '必须是同校',
     * 6 => '必须同城',
     * 7 => '必须是不同校',
     * 8 => '接受同省调剂',
     * 9 => '必须是同乡'
     */
    public function checkLike2All($girl, $boy)
    {
        if ($girl['pair_all'] == 0) {
            return false;
        }
        if ($boy['pair_all'] == 0) {
            return false;
        }
        // 是否匹配过
        if (in_array($boy['uid'], $girl['pairs'])) {
            return false;
        }
        // 性别-性取向
        if ($girl['sex'] != $boy['sxo'] || $boy['sex'] != $girl['sxo']) {
            return false;
        }
        // 年龄
        $boy_age = date('Y') - intval($boy['age']);
        $girl_age = date('Y') - intval($girl['age']);
        //begin
        if (
            ($girl['pair_min_age'] > 9
                || $boy['pair_min_age'] > 9)
            && abs($girl_age - $boy_age) > 4
        ) {
            return false;
        }

        if (
            $boy_age < ($girl_age - $girl['pair_min_age'])
            || $boy_age > ($girl_age + $girl['pair_max_age'])
            || $girl_age < ($boy_age - $boy['pair_min_age'])
            || $girl_age > ($boy_age + $boy['pair_max_age'])
        ) {
            return false;
        }

        // 身高
        if ($girl['sex'] != $boy['sex']) {
            if ($boy['sex'] == 1) { # 男boy女girl
                if ($boy['height'] < ($girl['height'] + 5)) {
                    return false;
                }
            } else { # 男girl女boy
                if ($girl['height'] < ($boy['height'] + 5)) {
                    return false;
                }
            }
        }
        // 勾选匹配条件
        $girl['likes'] = $girl['fpdx_like'] ? explode(',', trim($girl['fpdx_like'], ',')) : [];
        $boy['likes'] = $boy['fpdx_like'] ? explode(',', trim($boy['fpdx_like'], ',')) : [];
        foreach ($girl['likes'] as $girl_like) {
            $self = $girl;
            $other = $boy;
            switch ($girl_like) {
                case 1: // 年龄必须比我大; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小; 年龄差距最大4岁
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case -3:
                case -2:
                case -1:
                default:
                    break;
            }
        }
        foreach ($boy['likes'] as $boy_like) {
            $self = $boy;
            $other = $girl;
            switch ($boy_like) {
                case 1: // 年龄必须比我大
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age < $self_age) {
                        return false;
                    }
                    break;
                case 2: // 年龄必须比我小
                    $self_age = time() - strtotime($self['age']);
                    $other_age = time() - strtotime($other['age']);
                    if ($other_age > $self_age) {
                        return false;
                    }
                    break;
                case 3: // 身高必须比我高
                    if ($other['height'] <= $self['height']) {
                        return false;
                    }
                    break;
                case 4: // 身高必须比我矮
                    if ($other['height'] >= $self['height']) {
                        return false;
                    }
                    break;
                case 7: // 必须是不同校
                    if ($self['school'] == $other['school']) {
                        return false;
                    }
                    break;
                case -3:
                case -2:
                case -1:
                default:
                    break;
            }
        }
        return true;
    }

    /**
     * 匹配某期用户
     * @param  callable  $callback
     * @param  array  $argv
     * @return bool
     * @throws \Exception
     */
    public function pipei(callable $callback, array $argv)
    {
        $callback_checkLike = array(new self(), "checkLike");
        $callback_checkLike2Shenge = array(new self(), "checkLike2Sheng");
        $callback_checkLike2All = array(new self(), "checkLike2All");
        // 特权匹配 92
        dump("开始92特权匹配");
        $base_score = 92;
        // 完全符合条件
        dump("完全符合条件");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike, $base_score);
        // 允许同省调剂
        dump("同省调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2Shenge, $base_score);
        // 允许全国调剂
        dump("全国调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2All, $base_score);
        // 特权匹配 91
        dump("开始91特权匹配");
        $base_score = 91;
        // 完全符合条件
        dump("完全符合条件");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike, $base_score);
        // 允许同省调剂
        dump("同省调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2Shenge, $base_score);
        // 允许全国调剂
        dump("全国调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2All, $base_score);
        // 特权匹配 90
        dump("开始90特权匹配");
        $base_score = 91;
        // 完全符合条件
        dump("完全符合条件");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike, $base_score);
        // 允许同省调剂
        dump("同省调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2Shenge, $base_score);
        // 允许全国调剂
        dump("全国调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2All, $base_score);
        // 普通匹配
        dump("开始普通匹配");
        $base_score = 0;
        // 完全符合条件
        dump("完全符合条件");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike, $base_score);
        // 允许同省调剂
        dump("同省调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2Shenge, $base_score);
        // 允许全国调剂
        dump("全国调剂");
        $users = call_user_func_array($callback, $argv);
        $data = $tmp = $users->toArray();
        $this->init($data, $tmp, $callback_checkLike2All, $base_score);
        return true;
    }

    /**
     * 匹配包装器
     * @param  array  $data  待匹配数组1
     * @param  array  $tmp  待匹配数组2
     * @param  callable  $callback
     * @param  int  $base_score  基础匹配分
     * @return int 匹配成功的数量
     * @throws \Exception
     */
    public function init($data, $tmp, callable $callback, int $base_score = 0)
    {
        $count = 0;
        foreach ($data as $i => $value) {
            foreach ($tmp as $key => $item) {
                // 基础匹配分
                if ($value['score'] < $base_score && $item['score'] < $base_score) {
                    continue;
                }
                // 不可以匹配自己
                if ($value['uid'] == $item['uid']) {
                    continue;
                }
                // 是否满足条件
                if (call_user_func_array($callback, [$value, $item])) {
                    try {
                        DB::beginTransaction();
                        DB::table("kdgx_partner_charge_pair")
                            ->where('id', $value['pair_id'])->update([
                                'partner' => 1,
                                'assoc_id' => $item['pair_id']
                            ]);
                        DB::table("kdgx_partner_charge_pair")
                            ->where('id', $item['pair_id'])->update([
                                'partner' => 2,
                                'assoc_id' => $value['pair_id']
                            ]);
                        DB::commit();
                        $week4_12 = mktime(12, 0, 0, date('m'), date('d') - date('w') + 4, date('Y'));
                        $week5_12 = mktime(12, 0, 0, date('m'), date('d') - date('w') + 5, date('Y'));
                        if (time() > $week4_12 && time() < $week5_12) {
                            Redis::sadd("fpdx_pairs_{$value['uid']}", $item['uid']);
                            Redis::sadd("fpdx_pairs_{$item['uid']}", $value['uid']);
                        }
                        $count++;
                        unset($tmp[$key]);
                        break;
                    } catch (\Exception $e) {
                        DB::rollBack();
                        dump($e);
                        continue;
                    }
                } else {
                    continue;
                }
            }
        }
        return $count;
    }

    /**
     * 匹配
     * @param  int  $stage_id
     * @throws \Exception
     */
    public function index(int $stage_id = 0)
    {
        if (!$stage_id) {
            $stage_id = $this->getTodayStageId();
        }
        if ($stage_id) {
            if (app()->environment() == 'production') {
                Curl::to("http://api.deep.fenpeiduixiang.com/api/ding/paircp/begin/{$stage_id}")->get();
            }

            PairModel::where('stage_id', $stage_id)
                ->whereIn('media_id', ['gh_b598cb7474d8', 'gh_c94c95866ca5'])
                ->whereBetween('state', [0, 99])->increment('state', 100);
            $obj = new PairModel();
//            $this->pipei(array($obj, "getPairQuery"), [$stage_id, '72h', '浙江-杭州']);
//            $this->pipei(array($obj, "getPairQuery"), [$stage_id, 'qbj']);
            $this->pipei(array($obj, "getPairQuery"), [$stage_id, '72h']);

            if (app()->environment() == 'production') {
                \Curl::to("http://api.deep.fenpeiduixiang.com/api/ding/paircp/end/{$stage_id}")->get();
            }
            $check = new CheckService();
            $check->baocun($stage_id);
            $check->check($stage_id);
        }
    }

    /**
     * 预匹配
     * @param  int  $stageId
     * @throws \Exception
     */
    public function prePipei($stageId = 0)
    {
        if (0 == $stageId) {
            $activitys = ActivityModel::getActivitys();
            $stageId = $activitys['next'];
        }
        if ($stageId) {
            if (app()->environment() == 'production') {
                Curl::to("http://api.deep.fenpeiduixiang.com/api/ding/paircp/begin/{$stageId}")->get();
            }

            $obj = new PairModel();
//            $this->pipei(array($obj, "getPairQuery"), array($stageId, '72h', '浙江-杭州'));
            $this->pipei(array($obj, "getPairQuery"), array($stageId, '72h'));
//            $this->pipei(array($obj, "getPairQuery"), array($stageId, 'qbj'));
            if (app()->environment() == 'production') {
                Curl::to("http://api.deep.fenpeiduixiang.com/api/ding/paircp/end/{$stageId}")->get();
            }
            $check = new CheckService();
            $check->baocun($stageId);
            $check->check($stageId);
        }
    }

    /**
     * 预匹配数据恢复
     */
    public function preRestore()
    {
        $activitys = ActivityModel::getActivitys();
        $stage_id = $activitys['next'];
        $last = PairModel::orderBy('stage_id', 'desc')->first();
        if (collect($last)->isEmpty() || $last->stage_id != $stage_id) {
            Ding::robot([
                'title' => '[分配对象]预匹配|数据恢复',
                'text' => "数据恢复异常"
            ]);
            return;
        }
        PairModel::where([['stage_id', $stage_id], ['pair_type', 0]])->update(['assoc_id' => null, 'partner' => 0]);
        if (app()->environment() == 'production') {
            Ding::robot([
                'title' => '[分配对象]预匹配提醒|数据恢复',
                'text' => "数据恢复正常"
            ]);
        }
    }
}
