<?php

namespace app\command;

use app\admin\controller\AdminController;
use app\common\Error;
use app\model\Admins;
use app\model\Blacks;
use app\model\FilterMobiles;
use app\model\Finances;
use app\model\Logs;
use app\model\Orders;
use app\server\Douyin;
use app\server\Meituan;
use app\server\Kuaishou;
use app\server\Orders as ServerOrders;
use app\server\SMS;
use stdClass;
use support\Log;
use support\Redis;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SpiderDy extends Command
{
    protected static $defaultName = 'spider:dy';
    protected static $defaultDescription = '抖音订单拉取器';

    protected $_users = [];

    protected function configure()
    {
        $this->setName('spider:dy')
            ->setDescription('抖音订单拉取器')
            ->setDefinition(
                new InputDefinition(array(
                    new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
                    new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
                    new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
                ))
            );
    }

    protected function users($routeType)
    {
        // if (count($this->_users) > 0) return $this->_users;
        $users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
        $us = [];
        foreach ($users as $u) {
            $ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
            if (empty($ru)) continue;

            $_u = new stdClass();
            $_u->username = $u->id;
            $us[] = $_u;
        };
        $this->_users = $us;
        return $this->_users;
    }

    protected $_redis_pool = [];

    protected function poolUser($status = 0, $categoryDesc = '')
    {
        $routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
        $status .= $routeType;
        if (empty($this->_redis_pool[$status])) {
            $this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
            $users = $this->users($routeType);
            $_users = [];
            if (empty($this->_redis_pool[$status])) {
                foreach ($users as $user) {
                    $_users[$user->username] = 0;
                    Redis::hSet('CRM:Pool:' . $status, $user->username, 0);
                }
                $this->_redis_pool[$status] = $_users;
            } else {
                asort($this->_redis_pool[$status]);
                $key_users = array_keys($this->_redis_pool[$status]);
                $username = $key_users[0];
                $max = $this->_redis_pool[$status][$username];
                $_users = [];
                foreach ($users as $user) {
                    $_users[] = $user->username;
                    if (!in_array($user->username, $key_users)) {
                        $this->_redis_pool[$status][$username] = $max;
                        Redis::hSet('CRM:Pool:' . $status, $user->username, $max);
                    }
                }
                foreach ($this->_redis_pool[$status] as $username => $val) {
                    if (!in_array($username, $_users)) {
                        unset($this->_redis_pool[$status][$username]);
                        Redis::hDel('CRM:Pool:' . $status, $username);
                    }
                }
            }
        }

        $username = null;
        try {
            $pool = $this->_redis_pool[$status];
            if (empty($pool)) $pool = [];
            asort($pool);
            $keys = array_keys($pool);
//            if(!!config('app.debug', true)) return 1;
            if (empty($keys)) {
                Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户');
                throw new \Exception('没有可以分配的用户');
            }
            $username = $keys[0];
            $this->_redis_pool[$status][$username] += 1;
            Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
        } catch (\Exception $e) {
            Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', (array)json_encode($e));
            throw new \Exception('没有可以分配的用户');
        }
        return $username;
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // $name = $input->getArgument('name');
        $output->writeln('START spider:dy:'.date('Y-m-d H:i:s'));

        $os = $input->getOption('os');
        $orderid = $input->getOption('sn');
        $d = $input->getOption('day');
        if (empty($d)) {
            $d = 40;
        }

        if ($orderid) {
            $this->reloadStatus($orderid, $os, $output);
            return 1;
        }

        // echo "状态1\n";
        // $this->poolUser(1);
        // echo "状态2\n";
        // $this->poolUser(2);
        // echo "状态3\n";
        // $this->poolUser(3);
        // echo "状态4\n";
        // $this->poolUser(4);
        // echo "状态5\n";
        // $this->poolUser(5);
        // return 1;

        // $this->checks($output);
        // $output->writeln('CHECK spider:dy');

        // $day = new Douyin();
        // print_r($day->get(1));
        // return 1;

        // sleep(5);
//        $time = strtotime(date('Y-m-d'));
//        for ($i = 0; $i <= $d; $i++) {
//            $day = $time - $i * 24 * 3600;
//            $start = date('Y-m-d', $day);
//            $end = date('Y-m-d 23:59:59', $day);
//            $this->orders($start, $end, false);
//            // $this->_kuaishouOrder($start, $end, false);
//        }

        // 8点20 开始分配订单
        date_default_timezone_set('Asia/Shanghai');
        $startTime = strtotime(date('Y-m-d 08:20'));
        if (time() > $startTime) {
            $start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
            $end = date('Y-m-d 23:59:59');
            $this->orders($start, $end, false);
        }

        if (date('H') >= 1 && date('H') <= 7) {
            $this->reload($output);
        }

        $output->writeln('END spider:dy:'.date('Y-m-d H:i:s'));
        return self::SUCCESS;
    }

    private function checks($output)
    {
        $i = 0;
        while (true) {
            $i++;
            sleep(1);
            $val = Redis::Rpop('Travel:Order:check:lits');
            if (empty($val) || $i > 100) return;

            //{\"id\":35,\"check_sn\":\"1\\u963f\\u8fbe\\u6211\\u7684as\\u7684\"}
            $json = json_decode($val);
            $res = (new Meituan())->voucher($json->check_sn);

            //{"code":0,"message":"成功","data":{"orderId":"4944968014698378527","mobile":"18641285757","categoryId":100602,"travelDate":"2024-03-29","isConsumed":true,"categoryDesc":"出发地参团","travelBeginDate":"2024-03-29","travelEndDate":"2024-03-29"},"texInfo":null,"success":true,"fail":false}
            if ($res->code === 0) { //核销成功
                $order_id = $res->data->orderId;
                $item = Orders::where('os', 1)->where('sn', $order_id)->find();
                if (!$item) {
                    $this->orders($output, $order_id);
                    $item = Orders::where('os', 1)->where('sn', $order_id)->find();
                }

                if (empty($item)) {
                    Redis::Lpush('Travel:Order:check:lits', $val);
                    continue;
                }

                //
                $checkOrder = Orders::where('check_sn', $json->check_sn)->find();
                //不为空表示已经验证过了
                if (!empty($checkOrder)) {
                    continue;
                }

                //查看订单是否存在
                $back = false; //修改数据库成功了没有
                if (!empty($json->id)) {
                    $order = Orders::where('id', $json->id)->find();
                    if ($order->sn == $order_id) {
                        $order->is_check = 1;
                        $order->check_sn = $json->check_sn;
                        $back = $order->save();
                    }
                } elseif (!empty($json->admin_id)) {
                    //订单在自己的名下
                    $order = Orders::where('sn', $order_id)->where('admin_id', $json->admin_id)->find();
                    if (!empty($order)) {
                        $order->is_check = 1;
                        $order->check_sn = $json->check_sn;
                        $back = $order->save();
                        echo "订单在自己名下";
                    } else {
                        // echo "订单在自己名下2 $order_id";
                        $order = Orders::where('sn', $order_id)->find();
                        // print_r($order->toArray());
                        if (!empty($order) && $order->admin_id == 0) {
                            echo '订单不在自己的名下,并且没有分人。';
                            $order->is_check = 1;
                            $order->check_sn = $json->check_sn;
                            $order->admin_id = $json->admin_id;
                            $back = $order->save();
                        } elseif (!empty($order) && $order->admin_id !== $json->admin_id) {
                            echo '订单不在自己的名下,并且分人了。';
                            $item = new Orders();
                            $item->os = 1;
                            $item->sn = $order->sn;
                            $item->product_id = $order->product_id;
                            $item->product_name = $order->product_name;
                            $item->category_id = $order->category_id;
                            $item->create_at = $order->create_at;
                            $item->travel_date = $order->travel_date;
                            $item->mobile = $order->mobile;
                            $item->unit_price = $order->unit_price;
                            $item->total_price = $order->total_price;
                            $item->actual_price = $order->actual_price;
                            $item->quantity = $order->quantity;
                            $item->order_status = $order->order_status;
                            $item->refund_status = $order->refund_status;
                            $item->category_desc = $order->category_desc;
                            $item->admin_id = $json->admin_id;
                            $item->check_sn = $json->check_sn;
                            $item->is_check = 1;
                            $back = $item->save();

                            $order->is_change = $json->admin_id;
                            $back2 = $order->save();
                        }
                    }
                }

                if (!$back) {
                    Redis::Lpush('Travel:Order:check:lits', $val);  //写回去
                    Redis::Lpush('Travel:Order:check:lits:err', $val);
                }
            } else {
                if ($res->code == 12) {
                    if ($json->id > 0) {
                        //核销码无效
                        $order = Orders::where('id', $json->id)->find();
                        $order->is_check = 2;
                        $order->save();
                    }
                    Logs::create([
                        'admin_id' => $json->admin_id ?? 0,
                        'action' => 11,
                        'order_id' => $json->id ?? 0,
                        'check_sn' => $json->check_sn
                    ]);
                }
                if ($res->code > 0 && $res->code != 12) {
                    Redis::Lpush('Travel:Order:check:lits', $val);
                    Redis::Lpush('Travel:Order:check:lits:err', $val);
                }
            }
        }
    }

    private function orders($start = null, $end = null, $order_id = false)
    {

        foreach (Orders::OSS as $k => $os) {
            $pages = 6;
            $page = 1;

            while (true) {
                if ($page > $pages) break;
                $list = [];

                switch ($k) {
                    /*case 1:
                        try {
                            $mei = new Meituan();
                            $list = $mei->get($page, $start, $end);
                            $pages = $mei->totalPage;
                        } catch (\Exception $e) {
                            Log::error(dirname(__FILE__) . __LINE__ . $e);
                        }
                        break;*/

                    /*case 2:
                        try {
                            $kuai = new Kuaishou();
                            $list = $kuai->get($page, $start, $end);
                            $pages = $kuai->totalPage;
                        } catch (\Exception $e) {
                            Log::error(dirname(__FILE__) . __LINE__ . $e);
                        }
                        break;*/

                    case 3:
                    case 5:
//                        echo '==========pages='.$pages;
                        try {
                            $dou = new Douyin($k);
                            $list = $dou->get($page, $start, $end, '');
                            $pages = $dou->totalPage;
                        } catch (\Exception $e) {
                            Log::error(dirname(__FILE__) . __LINE__ . $e);
                        }
                        break;

                    default:
                        # code...
                        break;
                }

                foreach ($list as $order) {
                    // 过滤一日游
                    if ($order->os == 3 && strpos($order->category_desc, '一日游') !== false) {
                        Log::info("抖音 跳过订单:{$order->order_id}");
                        continue;
                    }

                    $item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();

                    if (empty($item)) {
                        $order->is_zhibo = $this->zhibo($order->product_name, $order->os);

                        if (FilterMobiles::isFilterMobile($order->mobile)) {
                            $admin_id = 0;
                        } else {
                            $oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
                                ->where("create_time", '>=', time() - 24 * 3600 * 3)->find();

                            if (!empty($oldMobile)) {
                                $admin_id = $oldMobile->admin_id;
                            } else {
                                $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
                            }

                            if (empty($admin_id)) return null;
                        }

                        $order->admin_id = $admin_id;
                        $order->give_time = time();
                        //判断是否需要发短信
                        if (($order->os == 1 && array_key_exists($order->order_status, [1 => 1, 3 => 3])) ||
                            ($order->os == 2 && array_key_exists($order->order_status, [2 => 2, 3 => 3, 4 => 4])) ||
                            ($order->os == 3 && $order->order_status == 1)) {
                        //    $this->sms($admin_id, $order);
                        }
                        //新获得一个用户的,提示管理员有新的订单
                        Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
                        $item = new Orders();
                    }

                    if ($order->travel_date && empty($order->travel_end)) {
                        $days = $this->_days($order);
                        if ($days) {
                            $order->travel_end = date('Y-m-d 00:00:00', strtotime($order->travel_date) + $days * 24 * 3600);
                        }
                    }

                    if ($item->order_status !== 2 && $order->order_status == 2) {
                        Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
                    }

                    $back = $item->save($order->toArray());

                    if ($back) {
                        $this->_finance(0, $item->id, $item->asset_price);
                    }
                }

                // 数据小于50, 结束
                if (count($list) < 50) {
                    break;
                }
                $page++;
            }
        }
    }

    private function reload($output)
    {
        $back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
        if (!$back) return;
        $orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 3)->wherein('status', [1, 2, 3])->select();
        foreach ($orders as $order) {
            $this->reloadStatus($order->sn, $order->os, $output);
        }
    }

    private function reloadStatus($orderid, $os, $output)
    {
        $w[] = ['sn', '=', $orderid];
        if ($os) $w[] = ['os', '=', $os];
        $item = Orders::where($w)->find();
        if (empty($item)) {
            $output->writeln('没有找到订单');
        }
        $it = null;
        switch ($item->os) {
            /*case 1:
                $m = new Meituan();
                $it = $m->get(1, null, null, $item->sn);
                break;
            case 2:
                $m = new Kuaishou();
                $it = $m->get(1, null, null, $item->sn);
                break;*/
            case 3:
            case 5:
                $m = new Douyin($item->os);
                $it = $m->get(1, null, null, $item->sn);
                break;

            default:
                # code...
                break;
        }

        if ($it) {
            $back = $item->save($it[0]);
            if ($back) {
                $this->_finance(0, $item->id, $item->asset_price);
            }
        } else {
            $output->writeln('没有拉取到数据:' . $orderid);
        }

    }

    private function _days($order)
    {
        if (stripos($order->product_name, '一日') !== false) {
            return 1;
        }
        preg_match('/(\d)天/', $order->product_name, $all);
        if (!empty($all) && intval($all[1]) > 0) {
            return $all[1];
        }
        return 0;
    }

    private function sms($admin_id, $order)
    {
        $user = Admins::cache(true)->where('id', $admin_id)->find();
        if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
            echo "发送短信\n";
            print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
            $has = Blacks::where('mobile', $order->mobile)->find();
            if (empty($has) && !empty($order->mobile)) {
                SMS::juhe_sms_send($order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]);
            } else {
                echo "黑名单不发送短信\n";
                sleep(10);
            }

        } else {
            echo "不发送短信\n";
            print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
        }
    }

    private function zhibo($title, $os = 0)
    {
        if ($os == 3) {

            return 2;
        }
        if (
            strlen($title) - 3 == strripos($title, "!")
            || strlen($title) - 1 == strripos($title, "!")
        ) {
            return 1;
        } elseif (strlen($title) - 3 == strripos($title, "甄")) {
            return 2;
        }
        return 0;
    }

    private function _finance($type = 1, $order_id = 0, $price = 0)
    {
        // $fa = Finances::where('order_id', $order_id)->where('type', $type)->find();
        $back = Redis::set('CRM:ORDER:LOCK:' . $order_id, time(), 'EX', 6, 'NX');
        if (!$back) return;

        $total = Finances::where('order_id', $order_id)->sum('total'); //总的关于这个订单的金额
        //如果总金额大于提交上来的核销金额,那就是退费的
        //如果提交上来的金额小于总金额,那就是核销的
        if ($total > $price) {
            $type = 2;
            $fee = -($total - $price);
        } elseif ($total < $price) {
            $type = 1;
            $fee = $price - $total;
        } else {
            return;
        }

        Finances::create([
            'order_id' => $order_id,
            'type' => $type,
            'total' => $fee,
            'status' => 1
        ]);
        return;

        // if(empty($fa)) {
        //     if($type == 2) {
        //         $has = Finances::where('order_id', $order_id)->where('type', 1)->find();
        //         if(empty($has)) return;
        //     }
        //     Finances::create([
        //         'order_id' => $order_id,
        //         'type' => $type,
        //         'total' => $price,
        //         'status' => 1
        //     ]);
        // }
    }
}