package com.ruoyi.web.modules.video.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.circulation.domain.BizTradeMarket;
import com.ruoyi.web.modules.circulation.mapper.BizTradeMarketMapper;
import com.ruoyi.web.modules.circulation.support.TradeMarketRules;
import com.ruoyi.web.modules.industryservice.domain.BizPasture;
import com.ruoyi.web.modules.industryservice.domain.vo.YakAssetSyncResultVo;
import com.ruoyi.web.modules.industryservice.mapper.BizPastureMapper;
import com.ruoyi.web.modules.video.domain.BizLivestockMonitor;
import com.ruoyi.web.modules.video.domain.MonitorOwnerOption;
import com.ruoyi.web.modules.video.mapper.BizLivestockMonitorMapper;
import com.ruoyi.web.modules.video.service.IBizLivestockMonitorService;
import com.ruoyi.web.modules.video.service.LivestockMonitorSyncService;
import com.ruoyi.web.modules.video.support.LivestockMonitorValidation;
import com.ruoyi.web.modules.video.support.LivestockMonitorRules;
import com.ruoyi.web.modules.video.support.LivestockMonitorOwnerResolver;
import com.ruoyi.web.modules.video.domain.vo.LivestockMonitorPlayUrlVo;
import com.ruoyi.web.modules.video.domain.dto.OpenCameraPlayUrlDto;
import com.ruoyi.web.modules.video.support.ThirdPartyCameraClient;

/**
 * 畜牧监控业务服务实现。
 * <p>
 * 职责划分：
 * <ul>
 *   <li>CRUD：经 {@link LivestockMonitorValidation} 校验后落库，主体信息经 {@link LivestockMonitorOwnerResolver} 解析</li>
 *   <li>列表/详情：填充 {@code ownerTypeName}、{@code videoSourceName} 供前端展示</li>
 *   <li>主体下拉：合并牧场与交易市场两个数据源，按名称排序</li>
 *   <li>同步：委托 {@link LivestockMonitorSyncService}</li>
 *   <li>实时预览：委托 {@link ThirdPartyCameraClient#fetchPlayUrl} 按 monitor_id 拉取播放地址</li>
 * </ul>
 * </p>
 */
@Service
public class BizLivestockMonitorServiceImpl implements IBizLivestockMonitorService
{
    @Autowired
    private BizLivestockMonitorMapper bizLivestockMonitorMapper;

    @Autowired
    private LivestockMonitorOwnerResolver ownerResolver;

    @Autowired
    private BizPastureMapper bizPastureMapper;

    @Autowired
    private BizTradeMarketMapper bizTradeMarketMapper;

    @Autowired
    private LivestockMonitorSyncService livestockMonitorSyncService;

    @Autowired
    private ThirdPartyCameraClient thirdPartyCameraClient;

    /** {@inheritDoc} 查询后填充展示字段 */
    @Override
    public BizLivestockMonitor selectBizLivestockMonitorById(Long id)
    {
        BizLivestockMonitor row = bizLivestockMonitorMapper.selectBizLivestockMonitorById(id);
        enrichRow(row);
        return row;
    }

    /** {@inheritDoc} 监控名称 trim 后模糊匹配 */
    @Override
    public List<BizLivestockMonitor> selectBizLivestockMonitorList(BizLivestockMonitor query)
    {
        if (query != null && StringUtils.isNotEmpty(query.getMonitorName()))
        {
            query.setMonitorName(query.getMonitorName().trim());
        }
        List<BizLivestockMonitor> list = bizLivestockMonitorMapper.selectBizLivestockMonitorList(query);
        if (list != null)
        {
            for (BizLivestockMonitor row : list)
            {
                enrichRow(row);
            }
        }
        return list;
    }

    /**
     * {@inheritDoc}
     * <p>
     * 分别从 {@code biz_pasture}（正常）与 {@code biz_trade_market}（正常营业）各取最多
     * {@link LivestockMonitorRules#OWNER_OPTIONS_LIMIT} 条，合并后按 {@code ownerName} 排序。
     * </p>
     */
    @Override
    public List<MonitorOwnerOption> selectOwnerOptions(String keyword)
    {
        String kw = StringUtils.isNotEmpty(keyword) ? keyword.trim() : null;
        List<MonitorOwnerOption> options = new ArrayList<>();

        BizPasture pastureQuery = new BizPasture();
        pastureQuery.setKeyword(kw);
        PageHelper.startPage(1, LivestockMonitorRules.OWNER_OPTIONS_LIMIT, false);
        List<BizPasture> pastures = bizPastureMapper.selectBizPastureList(pastureQuery);
        PageHelper.clearPage();
        if (pastures != null)
        {
            for (BizPasture p : pastures)
            {
                MonitorOwnerOption opt = new MonitorOwnerOption();
                opt.setOwnerType(LivestockMonitorRules.OWNER_TYPE_PASTURE);
                opt.setOwnerTypeName(LivestockMonitorRules.ownerTypeName(opt.getOwnerType()));
                opt.setOwnerId(p.getId());
                opt.setOwnerName(p.getPastureName());
                options.add(opt);
            }
        }

        BizTradeMarket marketQuery = new BizTradeMarket();
        marketQuery.setOperateStatus(TradeMarketRules.OPERATE_STATUS_NORMAL);
        if (StringUtils.isNotEmpty(kw))
        {
            marketQuery.setMarketName(kw);
        }
        PageHelper.startPage(1, LivestockMonitorRules.OWNER_OPTIONS_LIMIT, false);
        List<BizTradeMarket> markets = bizTradeMarketMapper.selectBizTradeMarketList(marketQuery);
        PageHelper.clearPage();
        if (markets != null)
        {
            for (BizTradeMarket m : markets)
            {
                MonitorOwnerOption opt = new MonitorOwnerOption();
                opt.setOwnerType(LivestockMonitorRules.OWNER_TYPE_TRADE_MARKET);
                opt.setOwnerTypeName(LivestockMonitorRules.ownerTypeName(opt.getOwnerType()));
                opt.setOwnerId(m.getId());
                opt.setOwnerName(m.getMarketName());
                options.add(opt);
            }
        }

        options.sort(Comparator.comparing(MonitorOwnerOption::getOwnerName,
                Comparator.nullsLast(String::compareTo)));
        return options;
    }

    /**
     * {@inheritDoc}
     * <p>所属主体可选：未填则清空 owner 三字段；已填则校验主体存在并写入 {@code owner_name} 冗余。</p>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertBizLivestockMonitor(BizLivestockMonitor row)
    {
        LivestockMonitorValidation.validateRowForSave(row);
        if (LivestockMonitorValidation.hasOwner(row))
        {
            ownerResolver.applyOwnerToRow(row);
        }
        else
        {
            row.setOwnerType(null);
            row.setOwnerId(null);
            row.setOwnerName(null);
        }
        row.setDelFlag(LivestockMonitorRules.DEL_FLAG_NORMAL);
        return bizLivestockMonitorMapper.insertBizLivestockMonitor(row);
    }

    /** {@inheritDoc} 须存在且 {@code del_flag=0} */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateBizLivestockMonitor(BizLivestockMonitor row)
    {
        if (row.getId() == null)
        {
            throw new ServiceException("主键不能为空");
        }
        requireActiveRow(row.getId());
        LivestockMonitorValidation.validateRowForSave(row);
        if (LivestockMonitorValidation.hasOwner(row))
        {
            ownerResolver.applyOwnerToRow(row);
        }
        else
        {
            row.setOwnerType(null);
            row.setOwnerId(null);
            row.setOwnerName(null);
        }
        row.setDelFlag(LivestockMonitorRules.DEL_FLAG_NORMAL);
        return bizLivestockMonitorMapper.updateBizLivestockMonitor(row);
    }

    /**
     * {@inheritDoc}
     * <p>跳过 null id；对已删除记录幂等忽略（不抛错）。</p>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteBizLivestockMonitorByIds(Long[] ids, String updateBy)
    {
        if (ids == null || ids.length == 0)
        {
            return 0;
        }
        List<Long> cleaned = new ArrayList<>();
        for (Long id : ids)
        {
            if (id != null)
            {
                cleaned.add(id);
            }
        }
        if (cleaned.isEmpty())
        {
            return 0;
        }
        for (Long id : cleaned)
        {
            BizLivestockMonitor row = bizLivestockMonitorMapper.selectBizLivestockMonitorByIdAny(id);
            if (row == null || LivestockMonitorRules.DEL_FLAG_DELETED.equals(row.getDelFlag()))
            {
                continue;
            }
        }
        return bizLivestockMonitorMapper.logicDeleteBizLivestockMonitorByIds(
                cleaned.toArray(new Long[0]), updateBy);
    }

    /** {@inheritDoc} */
    @Override
    public YakAssetSyncResultVo syncFromThirdParty(String operator)
    {
        return livestockMonitorSyncService.syncFromThirdParty(operator);
    }

    /** {@inheritDoc} */
    @Override
    public LivestockMonitorPlayUrlVo getPlayUrlByMonitorId(String monitorId)
    {
        String id = StringUtils.trim(monitorId);
        if (StringUtils.isEmpty(id))
        {
            throw new ServiceException("摄像头ID不能为空");
        }
        BizLivestockMonitor row = bizLivestockMonitorMapper.selectBizLivestockMonitorByMonitorId(id);
        if (row == null || LivestockMonitorRules.DEL_FLAG_DELETED.equals(row.getDelFlag()))
        {
            throw new ServiceException("监控点位不存在或已删除");
        }
        Long cameraId;
        try
        {
            cameraId = Long.parseLong(id);
        }
        catch (NumberFormatException e)
        {
            throw new ServiceException("摄像头ID格式无效");
        }
        OpenCameraPlayUrlDto playUrlDto = thirdPartyCameraClient.fetchPlayUrl(cameraId);
        LivestockMonitorPlayUrlVo vo = new LivestockMonitorPlayUrlVo();
        vo.setMonitorId(id);
        vo.setMonitorName(row.getMonitorName());
        String videoSource = playUrlDto.getVideoSource() != null
                ? playUrlDto.getVideoSource().trim().toLowerCase()
                : row.getVideoSource();
        vo.setVideoSource(videoSource);
        vo.setVideoSourceName(LivestockMonitorRules.videoSourceName(videoSource));
        vo.setVideoUrl(playUrlDto.getVideoUrl());
        return vo;
    }

    /** 查询未删除记录，不存在则抛业务异常 */
    private BizLivestockMonitor requireActiveRow(Long id)
    {
        BizLivestockMonitor row = bizLivestockMonitorMapper.selectBizLivestockMonitorById(id);
        if (row == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        return row;
    }

    /** 填充列表/详情展示用中文名称（非持久化字段） */
    private static void enrichRow(BizLivestockMonitor row)
    {
        if (row != null)
        {
            row.setOwnerTypeName(LivestockMonitorRules.ownerTypeName(row.getOwnerType()));
            row.setVideoSourceName(LivestockMonitorRules.videoSourceName(row.getVideoSource()));
        }
    }
}
