package tech.easyflow.admin.controller.system;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.relation.RelationManager;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.easyflow.common.util.StringUtil;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.log.annotation.LogRecord;
import tech.easyflow.system.entity.SysLog;
import tech.easyflow.system.service.SysLogService;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Collections;
import java.util.Date;

import static tech.easyflow.system.entity.table.SysAccountTableDef.SYS_ACCOUNT;
import static tech.easyflow.system.entity.table.SysLogTableDef.SYS_LOG;

/**
 * 操作日志表 控制层。
 *
 * @author michael
 * @since 2024-03-06
 */
@RestController
@RequestMapping("/api/v1/sysLog")
public class SysLogController extends BaseCurdController<SysLogService, SysLog> {

    private static final long MAX_PAGE_SIZE = 100L;
    private static final DateTimeFormatter QUERY_TIME_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 创建操作日志控制器。
     *
     * @param service 操作日志服务
     */
    public SysLogController(SysLogService service) {
        super(service);
    }

    /**
     * 构造通用查询条件，并追加操作时间范围。
     *
     * @param request 当前 HTTP 请求
     * @return 操作日志查询条件
     * @throws BusinessException 时间格式不正确或开始时间晚于结束时间时抛出
     */
    @Override
    protected QueryWrapper buildQueryWrapper(HttpServletRequest request) {
        QueryWrapper queryWrapper = super.buildQueryWrapper(request);
        String keyword = normalizeSearchKeyword(request.getParameter("keyword"));
        if (StringUtil.hasText(keyword)) {
            LoginAccount account = SaTokenUtil.getLoginAccount();
            String pattern = buildLiteralContainsPattern(keyword);
            QueryCondition accountKeyword = SYS_ACCOUNT.LOGIN_NAME.likeRaw(pattern)
                    .or(SYS_ACCOUNT.NICKNAME.likeRaw(pattern));
            QueryWrapper accountExists = QueryMethods.selectOne()
                    .from(SYS_ACCOUNT)
                    .where(SYS_ACCOUNT.ID.eq(SYS_LOG.ACCOUNT_ID))
                    .and(SYS_ACCOUNT.TENANT_ID.eq(account.getTenantId()))
                    .and(accountKeyword);
            QueryCondition keywordCondition = SYS_LOG.ACTION_NAME.likeRaw(pattern)
                    .or(SYS_LOG.ACTION_IP.likeRaw(pattern))
                    .or(QueryMethods.exists(accountExists));
            queryWrapper.and(keywordCondition);
        }
        Date createdStart = parseQueryTime(request.getParameter("createdStart"));
        Date createdEnd = parseQueryTime(request.getParameter("createdEnd"));
        if (createdStart != null && createdEnd != null && createdStart.after(createdEnd)) {
            throw new BusinessException(400, 400, "操作时间范围不正确");
        }
        if (createdStart != null) {
            queryWrapper.ge(SysLog::getCreated, createdStart);
        }
        if (createdEnd != null) {
            queryWrapper.le(SysLog::getCreated, createdEnd);
        }
        return queryWrapper;
    }

    /**
     * 按操作时间稳定倒序展示最新日志。
     *
     * @return 默认排序表达式
     */
    @Override
    protected String getDefaultOrderBy() {
        return "created desc, id desc";
    }

    /**
     * 限制日志单页记录数并加载操作账号关系。
     *
     * @param page 分页参数
     * @param queryWrapper 查询条件
     * @return 操作日志分页结果
     */
    @Override
    @LogRecord("分页查询")
    protected Page<SysLog> queryPage(Page<SysLog> page, QueryWrapper queryWrapper) {
        page.setPageSize(Math.min(page.getPageSize(), MAX_PAGE_SIZE));
        RelationManager.setQueryRelations(Collections.singleton("account"));
        return service.getMapper().paginateWithRelations(page, queryWrapper);
    }

    /**
     * 解析日志查询时间。
     *
     * @param value 格式为 yyyy-MM-dd HH:mm:ss 的时间文本
     * @return 解析后的时间；空文本返回 {@code null}
     * @throws BusinessException 时间格式不正确时抛出
     */
    private Date parseQueryTime(String value) {
        if (!StringUtil.hasText(value)) {
            return null;
        }
        try {
            LocalDateTime dateTime = LocalDateTime.parse(value, QUERY_TIME_FORMATTER);
            return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
        } catch (DateTimeParseException exception) {
            throw new BusinessException(
                    400, 400, "操作时间格式不正确", exception);
        }
    }
}
