/*
 *
 *  * | Licensed 未经许可不能去掉「OPENIITA」相关版权
 *  * +----------------------------------------------------------------------
 *  * | Author: xw2sy@163.com
 *  * +----------------------------------------------------------------------
 *
 *  Copyright [2024] [OPENIITA]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * /
 */

package cc.iotkit.data.service;

import cc.iotkit.common.api.PageRequest;
import cc.iotkit.common.api.Paging;
import cc.iotkit.common.utils.MapstructUtils;
import cc.iotkit.common.utils.StringUtils;
import cc.iotkit.data.dao.AlertRecordRepository;
import cc.iotkit.data.dao.IJPACommData;
import cc.iotkit.data.manager.IAlertRecordData;
import cc.iotkit.data.model.QTbAlertRecord;
import cc.iotkit.data.model.TbAlertRecord;
import cc.iotkit.data.util.PageBuilder;
import cc.iotkit.data.util.PredicateBuilder;
import cc.iotkit.model.alert.AlertRecord;
import cc.iotkit.model.stats.AlertStatDTO;
import cc.iotkit.model.system.SysLoginInfo;
import cn.hutool.core.util.ObjectUtil;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cc.iotkit.data.model.QTbAlertRecord.tbAlertRecord;

@Primary
@Service
public class AlertRecordDataImpl implements IAlertRecordData, IJPACommData<AlertRecord, Long> {

    @Autowired
    private AlertRecordRepository alertRecordRepository;

    @Autowired
    private JPAQueryFactory jpaQueryFactory;

    @Override
    public JpaRepository getBaseRepository() {
        return alertRecordRepository;
    }

    @Override
    public Class getJpaRepositoryClass() {
        return TbAlertRecord.class;
    }

    @Override
    public Class getTClass() {
        return AlertRecord.class;
    }

    private static Predicate genPredicate(AlertRecord data) {
        boolean flag = false;
        if(ObjectUtils.isNotEmpty(data.getParams()) && !"".equals(data.getParams().get("endTime"))){
            flag = true;
        }
        if(ObjectUtils.isNotEmpty(data)) {
            return PredicateBuilder.instance()
                    .and(StringUtils.isNotBlank(data.getName()), () -> tbAlertRecord.name.like(data.getName()))
                    .and(StringUtils.isNotBlank(data.getLevel()), () -> tbAlertRecord.level.eq(data.getLevel()))
                    .and(flag, () -> (BooleanExpression) genTimePredicate(data.getParams()))
                    .build();
        }else{
            return PredicateBuilder.instance()
                    //.and(data != null && StringUtils.isNotBlank(data.getLevel()), () -> tbAlertRecord.level.eq(data.getLevel()))
                    .build();
        }
    }

    @Override
    public Paging<AlertRecord> selectAlertConfigPage(PageRequest<AlertRecord> request) {

            QueryResults<TbAlertRecord> results = jpaQueryFactory.selectFrom(tbAlertRecord)
                    .where(genPredicate(request.getData()))
                //    .where(genTimePredicate(request.getData().getParams())) // 添加时间条件
                    .orderBy(tbAlertRecord.id.desc())
                    .limit(request.getPageSize())
                    .offset(request.getOffset()).fetchResults();
        // 将alertTime乘以1000
        List<TbAlertRecord> convertedResults = results.getResults().stream()
                .peek(record -> record.setAlertTime(record.getAlertTime() * 1000))
                .collect(Collectors.toList());

        return new Paging<>(results.getTotal(), convertedResults).to(AlertRecord.class);

    }
    private static Predicate genTimePredicate(Map params) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate beginDate = LocalDate.parse(params.get("beginTime").toString(), formatter);
        LocalDate endDate = LocalDate.parse(params.get("endTime").toString(), formatter);

        long beginSec = beginDate.atStartOfDay(ZoneId.systemDefault())
                .toEpochSecond();
        long endSec = endDate.atTime(23, 59, 59)
                .atZone(ZoneId.systemDefault())
                .toEpochSecond();
        /*return  PredicateBuilder.instance()
                .and(tbAlertRecord.alertTime.between(beginSec, endSec));*/
        return tbAlertRecord.alertTime.between(beginSec, endSec);
    }

    @Override
    public List<AlertStatDTO> getAlertRecord() {

      /*  QueryResults<TbAlertRecord> results = jpaQueryFactory.selectFrom(tbAlertRecord).where(genPredicate(request.getData()))
                .orderBy(tbAlertRecord.id.desc())
                .limit(request.getPageSize())
                .offset(request.getOffset()).fetchResults();*/
        long currentTime = Instant.now().getEpochSecond();
        long sevenDaysAgo = currentTime - (7 * 24 * 60 * 60);
        QTbAlertRecord record = QTbAlertRecord.tbAlertRecord;
        return jpaQueryFactory
                .select(Projections.constructor(
                        AlertStatDTO.class,
                        Expressions.stringTemplate("DATE_FORMAT(FROM_UNIXTIME({0}), '%Y-%m-%d')", record.alertTime).as("axis"),
                        record.level.as("name"),
                        record.count().as("data")
                ))
                .from(record)
                .where(record.alertTime.between(sevenDaysAgo, currentTime))
                .groupBy(
                        Expressions.stringTemplate("DATE_FORMAT(FROM_UNIXTIME({0}), '%Y-%m-%d')", record.alertTime),
                        record.level
                )
                .orderBy(
                        Expressions.stringTemplate("DATE_FORMAT(FROM_UNIXTIME({0}), '%Y-%m-%d')", record.alertTime).asc(),
                        record.level.asc()
                )
                .fetch();
    }
}
