<?php


namespace frontend\modules\api\controllers;


use common\models\AccidentCasesRelateToDictionary;
use common\models\AccidentCasesStudy;
use common\models\Dictionary;
use common\models\EmergencyResponseRelateToRulesPoints;
use common\models\OperationalAdjustmentsRelateToRulesPoints;
use common\models\SearchHistory;
use common\services\AdminLogService;
use common\services\CaseService;
use common\services\EmergencyResponseService;
use common\services\EventOverviewService;
use common\services\OperationalAdjustmentsService;
use common\services\RulesPointsService;
use common\services\RulesService;
use Exception;
use frontend\modules\api\components\BaseAdminController;
use Yii;
use yii\base\InvalidConfigException;
use yii\web\Response;

class CaseController extends BaseAdminController
{
    /**
     * 搜索历史
     * @return Response
     */
    public function actionSearchHistory()
    {
        $SearchHistoryList = SearchHistory::find()->where(["uid" => $this->uid])->orderBy("update_time desc")->asArray()->limit(10)->all();
        if (isset($SearchHistoryList[9])) {
            //个人历史记录超过10条，就删掉
            SearchHistory::deleteAll(["and", ["uid" => $this->uid], ["<", "update_time", $SearchHistoryList[9]["update_time"]]]);
        }
        $list = array_column($SearchHistoryList, "content");
        return $this->asJson($list);
    }

    /**
     * 推荐案例
     * @param $accident_id
     * @return Response
     * @throws Exception
     */
    public function actionRecommend($accident_id)
    {
        /**
         * 推荐顺序为：1.相同的事件类型，2.相同的时间特征，3.相同的发生位置。
         * 逻辑：
         * 先找到相同的事件类型，
         * 如果没有，找相同的时间特征，如果没有，找相同的发生位置，如果没有，返回空
         * 如果有，找出10个
         * 如果不足10个，找相同的时间特征替代
         * 如果总数仍不足10个，找相同的发生位置。
         * 最多显示10条记录
         */
        $limit = 10;
        $AccidentCases = CaseService::getCaseById($accident_id);
        //事件类型目前按照一级字段来推荐
        $AccidentCasesList = CaseService::getCaseShowQuery()->andWhere(["and", ["type_first" => $AccidentCases->type_first], ["<>", "id", $AccidentCases->id]])->limit($limit)->orderBy("start_time desc")->all();
        $list = CaseService::dealWithFocusList($AccidentCasesList);
        $totalCount = count($list);
        if ($totalCount < $limit) {
            //查找相同时间特征
            $idNotIn = array_column($AccidentCasesList, "id");
            $AccidentCasesList = CaseService::getCaseShowQuery()->andWhere(["and", ["time_type" => $AccidentCases->time_type], ["<>", "id", $AccidentCases->id], ["NOT IN", "id", $idNotIn]])->limit($limit - $totalCount)->orderBy("start_time desc")->all();
            $list = array_merge($list, CaseService::dealWithFocusList($AccidentCasesList));
        }
        $totalCount = count($list);
        if ($totalCount < $limit) {
            //查找相同的发生位置
            $idNotIn = array_column($AccidentCasesList, "id");
            $AccidentCasesList = CaseService::getCaseShowQuery()->andWhere(["and", ["position_base_second" => $AccidentCases->position_base_second], ["position_extra_second" => $AccidentCases->position_extra_second], ["<>", "id", $AccidentCases->id], ["NOT IN", "id", $idNotIn]])->limit($limit - $totalCount)->orderBy("start_time desc")->all();
            $list = array_merge($list, CaseService::dealWithFocusList($AccidentCasesList));
        }
        $data["data"] = $list;
        return $this->asJson($data);
    }

    /**
     * 案例搜索
     * @param int $current
     * @param int $page
     * @return Response
     * @throws InvalidConfigException
     */
    public function actionListNew(int $current = 1, int $page = 10)
    {
        //通用
        $post = Yii::$app->request->post();
        $query = CaseService::getCaseShowQuery()
            ->limit($page)
            ->offset(($current - 1) * $page);
        //排序
        $this->initSequence($query, "start_time desc");
        //搜索
        if (!isset($post["action"])) {
            $post["action"] = "fulltext";
        }
        $needSaveHistoryLog = true;
        if ($post["action"] == "fulltext") {
            //全文搜索
            list($info, $total) = $this->fullSearch($query, $post);
            //保存搜索记录
            if (trim($post["fulltext_content"]) != "") {
                $SearchHistory = SearchHistory::findOne(["uid" => $this->uid, "content" => trim($post["fulltext_content"])]);
                if (!$SearchHistory) {
                    $SearchHistory = new SearchHistory();
                    $SearchHistory->uid = $this->uid;
                    $SearchHistory->content = trim($post["fulltext_content"]);
                    $SearchHistory->type = 1;
                }
                $SearchHistory->update_time = time();
                $SearchHistory->save();
            } else {
                if ($current == 1 && $page == 5) {
                    $needSaveHistoryLog = false;
                }
            }
        } elseif ($post["action"] == "list") {
            //列表搜索
            list($info, $total) = $this->listSearch($query, $post);
        } else {
            //高级搜索
            list($info, $total) = $this->advanceSearch($query, $post);
        }
        //
        if ($needSaveHistoryLog) {
            $model = "";
            $origin = AdminLogService::getOrigin($model, $this->getAllParams());
            AdminLogService::saveLogWithUpdateHistory($origin, $model, 0, "", $this->getAllParams());
        }
        //
        $data["data"] = CaseService::dealWithList($info);
        $data["total"] = $total;
        return $this->asJson($data);
    }

    protected function fullSearch($query, $post)
    {
        $fulltextContent = trim($post["fulltext_content"]);
        if ($fulltextContent != "") {
            //先从字典表进行模糊查询，找出id并找到对应的表进行匹配
            $DictionaryIdList = array_column(Dictionary::find()->where(["and", ["<>", "pid", 0], ["like", "name", $fulltextContent]])->all(), "id");
            $AccidentCasesRelationship = array_column(AccidentCasesRelateToDictionary::find()->where(["accident_cases_id" => $DictionaryIdList])->select("distinct(accident_cases_id)")->asArray()->all(), "accident_cases_id");
            //规章制度
            $rulesList = RulesService::getQuery()->where(["or", ["like", "rule_name", $fulltextContent], ["like", "rule_content", $fulltextContent]])->asArray()->all();
            $rulesIds = array_column($rulesList, "id");
            $rulesPointsList = RulesPointsService::getRulesPointsQuery()->where([
                "or",
                ["like", "name", $fulltextContent],
                ["like", "content", $fulltextContent],
                ["rule_id" => $rulesIds]
            ])->asArray()->all();
            $rulesPointsIds = array_column($rulesPointsList, "id");
            //通过规章点找出相关的应急处置和运营调整
            $EmergencyResponseIds = array_column(EmergencyResponseRelateToRulesPoints::find()->where(["rules_point_id" => $rulesPointsIds])->all(), "emergency_response_id");
            $OperationalAdjustmentsIds = array_column(OperationalAdjustmentsRelateToRulesPoints::find()->where(["rules_point_id" => $rulesPointsIds])->all(), "operational_adjustments_id");
            //将事件概览、应急处置和运营调整的搜索加进来
            $EmergencyResponseList = EmergencyResponseService::getEmergencyResponseQuery()
                ->andWhere([
                    "or",
                    ["like", "content", $fulltextContent],
                    ["like", "important_content", $fulltextContent],
                    ["like", "assess", $fulltextContent],
                    ["like", "assess_two", $fulltextContent],
                    ["id" => $EmergencyResponseIds],
                ])
                ->select("distinct(accident_id)")
                ->asArray()->all();
            $EmergencyResponse = array_column($EmergencyResponseList, "accident_id");
            $EventOverviewList = EventOverviewService::getEventOverviewQuery()
                ->andWhere([
                    "or",
                    ["like", "content", $fulltextContent],
                    ["like", "important_content", $fulltextContent],
                    ["like", "assess", $fulltextContent],
                    ["like", "assess_two", $fulltextContent],
                    ["id" => $OperationalAdjustmentsIds],
                ])
                ->select("distinct(accident_id)")
                ->asArray()->all();
            $EventOverview = array_column($EventOverviewList, "accident_id");
            $OperationalAdjustmentsList = OperationalAdjustmentsService::getQuery()
                ->andWhere([
                    "or",
                    ["like", "content", $fulltextContent],
                    ["like", "important_content", $fulltextContent],
                    ["like", "assess", $fulltextContent],
                    ["like", "assess_two", $fulltextContent],
                ])
                ->select("distinct(accident_id)")
                ->asArray()->all();
            $OperationalAdjustments = array_column($OperationalAdjustmentsList, "accident_id");
            //整合ids
            $ids = array_merge($AccidentCasesRelationship, $EmergencyResponse, $EventOverview, $OperationalAdjustments);
            $ids = array_values(array_unique($ids));
            $query->andWhere([
                "or",
                ["id" => $ids],
                ["like", "title", $fulltextContent],
                ["like", "train_number_times", $fulltextContent],
                ["like", "position", $fulltextContent],
            ]);
        }
        //组合数据
        return [$query->all(), $query->count()];
    }

    protected function listSearch($query, $post)
    {
        //应急处置表字段 emergency_response_type  emergency_response fault  abnormal
        $post["emergency_response_type"] = [];
        $post["emergency_response"] = "";
        //运营调整字段  operational_adjustments_type operational_adjustments
        $post["operational_adjustments_type"] = [];
        $post["operational_adjustments"] = "";
        // ids
        $ids = [];
        //post数据
        $hasIdsSearch = false;
        foreach ($post["list_content"] as $value) {
            if ($value["count"] != []) {
                switch ($value["name"]) {
                    case "事件性质":
                        $query = $this->addArrayConditionToQuery("level", $query, $value["count"]);
                        break;
                    case "事件类型":
                        //事件类型 数组保存
                        $AccidentCasesRelationship = array_column(AccidentCasesRelateToDictionary::find()->where(["dictionary_id" => $value["count"]])->select("distinct(accident_cases_id)")->asArray()->all(), "accident_cases_id");
                        $ids = array_merge($ids, $AccidentCasesRelationship);
                        $hasIdsSearch = true;
                        break;
                    case "所属线路":
                        $query = $this->addArrayConditionToQuery("line", $query, $value["count"]);
                        break;
                    case "日期特征":
                        $query = $this->addArrayConditionToQuery("day_type", $query, $value["count"]);
                        break;
                    case "时间特征":
                        $query = $this->addArrayConditionToQuery("time_type", $query, $value["count"]);
                        break;
//                    case "应急处置信息":
//                        $post["emergency_response_type"] = $value["count"];
//                        break;
//                    case "运营调整信息":
//                        $post["operational_adjustments_type"] = $value["count"];
//                        break;
                    case "最大晚点":
                        $orData = ["or"];
                        $delayDataNums = 0;
                        foreach ($value["count"] as $count) {
                            $condition = $this->getMaximumDelay($count);
                            if (isset($condition[0]) && isset($condition[1])) {
                                $orData[] = ["and", [">=", "maximum_delay", $condition[0]], ["<=", "maximum_delay", $condition[1]]];
                            } else if (isset($condition[0])) {
                                $orData[] = [">=", "maximum_delay", $condition[0]];
                            }
                            $delayDataNums++;
                        }
                        if ($delayDataNums == 1) {
                            $query->andWhere($orData[1]);
                        } else {
                            $query->andWhere($orData);
                        }
                        break;
                    case "所属年份":
                        $this->setYearSearch($query, $value["count"]);
                        break;
                    default:
                        break;
                }
            }
        }

//        //应急处置表字段
//        $ids = array_merge($ids, $this->getIdsByEmergencyResponse($post));
//        //运营调整字段
//        $ids = array_merge($ids, $this->getIdsByOperationalAdjustments($post));
        if ($ids != []) {
            $query->andWhere(["id" => $ids]);
        }
        if ($hasIdsSearch && $query->where === ["delete_time" => 0, "status" => 1]) {
            //在有ids搜索的前提下其他搜索都没有
            return [[], 0];
        }
        //组合数据
        return [$query->all(), $query->count()];
    }

    protected function getMaximumDelay($maximum_delay)
    {
        $maximumDelayArray = [
            [0, 0],
            [2, 5],
            [5, 15],
            [15, 30],
            [30]
        ];
        return $maximumDelayArray[$maximum_delay];
    }

    protected function setYearSearch($query, $yearDictionaryIds)
    {
        $orData = ["or"];
        $delayDataNums = 0;
        /** @var Dictionary[] $yearInfoList */
        $yearInfoList = Dictionary::find()->where(["status" => 1, "id" => $yearDictionaryIds])->all();
        foreach ($yearInfoList as $yearInfo) {
            $yearStart = strtotime($yearInfo->name . "-01-01");
            $yearEnd = strtotime($yearInfo->name . "-12-31");
            $orData[] = ["and", [">=", "start_time", $yearStart], ["<=", "start_time", $yearEnd]];
            $delayDataNums++;
        }
        if ($delayDataNums == 1) {
            $query->andWhere($orData[1]);
        } else {
            $query->andWhere($orData);
        }
    }

    protected function advanceSearch($query, $post)
    {
        $hasIdsSearch = false;
        $ids = [];
        $dictionaryIds = [];
        //主要筛选条件
        if ($post["years"] !== []) {
            $this->setYearSearch($query, $post["years"]);
        }
        //字符串
        $query = $this->addConditionToQuery("title", $query, true);
        //下拉框
        $query = $this->addConditionToQuery("level", $query);
        if ($post["type_base"] !== []) {
            $dictionaryIds = array_merge($dictionaryIds, $post["type_base"]);
        }
        if (isset($post["duty_category"])) {
            $dictionaryIds[] = $post["duty_category"];
        }
//        $query = $this->addConditionToQuery("duty_category", $query);
        $query = $this->addConditionToQuery("day_type", $query);
        $query = $this->addConditionToQuery("time_type", $query);
        //时间范围
        $query = $this->addStartEndConditionToQuery("start_time", $query, true);
        $query = $this->addStartEndConditionToQuery("elimination_time", $query, true);
        $query = $this->addStartEndConditionToQuery("recovery_time", $query, true);
        //下拉框
        //发生位置
        if ($post["position_base_second"] !== "") {
            $dictionaryIds[] = $post["position_base_second"];
        }
        if ($post["substation_type"] !== "") {
            $dictionaryIds[] = $post["substation_type"];
        }
//        if(isset($post["train_number"])){
//            $dictionaryIds[] = $post["train_number"];
//        }
        $query = $this->addConditionToQuery("train_number", $query);
//        $query = $this->addConditionToQuery("substation_type", $query);
        $query = $this->addConditionToQuery("line", $query);
        $query = $this->addConditionToQuery("automation_level", $query);
        $query = $this->addConditionToQuery("train_group", $query);
        $query = $this->addConditionToQuery("train_model", $query);
        $query = $this->addConditionToQuery("incidence", $query);
        //数字min&&max array[0],array[1]
        $query = $this->addStartEndConditionToQuery("headway", $query);
        $query = $this->addStartEndConditionToQuery("online_trains_number", $query);
        $query = $this->addStartEndConditionToQuery("emergency_duration", $query);
        $query = $this->addStartEndConditionToQuery("affect_trains_number", $query);
        $query = $this->addStartEndConditionToQuery("power_loss_duration", $query);
        if (isset($post["maximum_delay"])) {
            $maximumDelay = $this->getMaximumDelay($post["maximum_delay"]);
            if ($maximumDelay < 4) {
                $query = $this->addStartEndConditionToQuery("maximum_delay", $query, false, $maximumDelay);
            } else {
                $query = $query->andWhere([">=", "maximum_delay", $maximumDelay]);
            }
        }
        $query = $this->addStartEndConditionToQuery("train_delayed_two_minutes", $query);
        $query = $this->addStartEndConditionToQuery("train_delayed_five_minutes", $query);
        $query = $this->addStartEndConditionToQuery("get_off_trains_number", $query);
        $query = $this->addStartEndConditionToQuery("skip_stop_trains_number", $query);
        //计算案例关系表
        if ($dictionaryIds != []) {
            $AccidentCasesRelationship = array_column(AccidentCasesRelateToDictionary::find()->where(["dictionary_id" => $dictionaryIds])->select("distinct(accident_cases_id)")->asArray()->all(), "accident_cases_id");
            $ids = array_merge($dictionaryIds, $AccidentCasesRelationship);
            $hasIdsSearch = true;
        }
        //附加表字段

        //应急处置表字段 emergency_response_type  emergency_response fault  abnormal
        if (isset($post["emergency_response_type"]) && $post["emergency_response_type"] != null) {
            $post["emergency_response_type"] = [$post["emergency_response_type"]];
            $ids = array_merge($ids, $this->getIdsByEmergencyResponse($post));
            $hasIdsSearch = true;
        }
        //事件概览字段  event_overview
        if (isset($post["event_overview"]) && $post["event_overview"] != "") {
            $EventOverview = array_column(EventOverviewService::getEventOverviewQuery()->andWhere(["like", "content", $post["event_overview"]])->select("distinct(accident_id)")->asArray()->all(), "accident_id");
            $ids = array_merge($ids, $EventOverview);
            $hasIdsSearch = true;
        }
        //运营调整字段  operational_adjustments_type operational_adjustments
        if (isset($post["operational_adjustments_type"]) && $post["operational_adjustments_type"] != "") {
            $post["operational_adjustments_type"] = [$post["operational_adjustments_type"]];
            $ids = array_merge($ids, $this->getIdsByOperationalAdjustments($post));
            $hasIdsSearch = true;
        }
        if ($ids != []) {
            $query->andWhere(["id" => $ids]);
        }
        error_log(json_encode($ids));
        if ($hasIdsSearch && $query->where === ["delete_time" => 0, "status" => 1]) {
            //在有ids搜索的前提下其他搜索都没有
            return [[], 0];
        }
        //组合数据
        return [$query->all(), $query->count()];
    }

    protected function getIdsByOperationalAdjustments($post)
    {
        $ids = [];
        if ($post["operational_adjustments_type"] != [] || $post["operational_adjustments"] != "") {
            $OperationalAdjustments = OperationalAdjustmentsService::getQuery();
            if ($post["operational_adjustments_type"] != []) {
                $OperationalAdjustments->andWhere(["type_first" => $post["operational_adjustments_type"]]);
            }
            if ($post["operational_adjustments"] != "") {
                $OperationalAdjustments->andWhere(["content" => $post["operational_adjustments"]]);
            }
            $OperationalAdjustments = array_column($OperationalAdjustments->select("distinct(accident_id)")->asArray()->all(), "accident_id");
            $ids = array_merge($ids, $OperationalAdjustments);
        }
        return $ids;
    }

    protected function getIdsByEmergencyResponse($post)
    {
        $ids = [];
        if ($post["emergency_response_type"] != [] || $post["emergency_response"] != "") {
            $EmergencyResponse = EmergencyResponseService::getEmergencyResponseQuery();
            if ($post["emergency_response_type"] != []) {
                $EmergencyResponse->andWhere(["type_first" => $post["emergency_response_type"]]);
            }
            if ($post["emergency_response"] != "") {
                $EmergencyResponse->andWhere(["like", "content", $post["emergency_response"]]);
            }
            $EmergencyResponse = array_column($EmergencyResponse->select("distinct(accident_id)")->asArray()->all(), "accident_id");
            $ids = array_merge($ids, $EmergencyResponse);
        }
        return $ids;
    }

    /**
     * 案例详情
     * @param $id
     * @return Response
     * @throws Exception
     */
    public function actionDetail($id): Response
    {
        $data = CaseService::getCaseDetail($id, "detail");
        //返回数据
        $model = "";
        $origin = AdminLogService::getOrigin($model, $this->getAllParams());
        AdminLogService::saveLogWithUpdateHistory($origin, $model, $data["id"], $data["title"], $this->getAllParams());
        return $this->asJson($data);
    }

    /**
     * 案例详情(通过日历里面点查看)
     * @param $id
     * @return Response
     * @throws Exception
     */
    public function actionDetailLog($id): Response
    {
        $data = CaseService::getCaseDetail($id, "detail");
        return $this->asJson($data);
    }

    /**
     * 案例对比
     * @param $ids
     * @return Response
     * @throws Exception
     */
    public function actionCompare($ids): Response
    {
        $ids = explode(",", $ids);
        $data = [];
        foreach ($ids as $id) {
            $data[] = CaseService::getCaseDetail($id, "detail");
        }
        return $this->asJson($data);
    }

    /**
     * @throws InvalidConfigException
     */
    public function actionStudyList(int $current = 1, int $page = 10)
    {
        $query = AccidentCasesStudy::find()->alias("s")
            ->join('LEFT JOIN', 'accident_cases a', 'a.id = s.accident_id')
            ->select(CaseService::getCaseStudySqlSelectInfo())
            ->asArray()
            ->limit($page)->offset(($current - 1) * $page);
        $this->initSequence($query, "s.id desc");
        $query = $this->addConditionToQueryNew('s.username','username', $query, true);
        $query = $this->addConditionToQueryNew('s.name','name', $query, true);
        $query = $this->addConditionToQueryNew('a.title','title', $query, true);
        $query = $this->addStartEndConditionToQueryNew("s.start_time",'start_time', $query);
        $data['data'] = $query->all();
        $data['total'] = $query->count();
        return $this->asJson($data);
    }

    /**
     * @throws InvalidConfigException
     */
    public function actionMyStudyList(int $current = 1, int $page = 10)
    {
        $query = AccidentCasesStudy::find()->alias("s")
            ->join('LEFT JOIN', 'accident_cases a', 'a.id = s.accident_id')
            ->select(CaseService::getCaseStudySqlSelectInfo())
            ->asArray()
            ->limit($page)->offset(($current - 1) * $page);
        $this->initSequence($query, "s.id desc");
        $query = $this->addConditionToQueryNew('s.username', $query, true);
        $query = $this->addConditionToQueryNew('s.name', $query, true);
        $query = $this->addConditionToQueryNew('a.title', $query, true);
        $query = $this->addStartEndConditionToQueryNew("s.start_time", $query);
        $query = $query->andWhere(["uid" => $this->userInfo->id]);
        $data['data'] = $query->all();
        $data['total'] = $query->count();
        return $this->asJson($data);
    }
}