package com.ruoyi.web.modules.video.support;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.industryservice.domain.dto.OpenApiPageResult;
import com.ruoyi.web.modules.industryservice.domain.dto.OpenApiResponse;
import com.ruoyi.web.modules.industryservice.support.ThirdPartyFarmingHttpSupport;
import com.ruoyi.web.modules.industryservice.support.ThirdPartyFarmingProperties;
import com.ruoyi.web.modules.video.domain.dto.OpenCameraDto;
import com.ruoyi.web.modules.video.domain.dto.OpenCameraPlayUrlDto;
import com.ruoyi.web.modules.video.support.LivestockMonitorSyncRules;

/**
 * 第三方监控客户端：stub 读取 classpath JSON；http 分页调用开放接口。
 * <p>
 * 列表：{@code GET /open-api/v1/iot/cameras}；播放地址：{@code GET /open-api/v1/iot/cameras/{cameraId}/play-url}。
 * 鉴权与 {@link ThirdPartyFarmingHttpSupport}、{@link ThirdPartyFarmingProperties} 与牧场同步共用。
 * </p>
 */
@Component
public class ThirdPartyCameraClientImpl implements ThirdPartyCameraClient
{
    /** stub 模式：监控列表样例 */
    private static final String STUB_RESOURCE = "thirdparty/stub-cameras.json";

    /** stub 模式：播放地址样例（按 cameraId 匹配） */
    private static final String STUB_PLAY_URL_RESOURCE = "thirdparty/stub-camera-play-urls.json";

    /** 查询监控数据（分页） */
    private static final String LIST_PATH = "/open-api/v1/iot/cameras";

    /** 获取监控视频播放地址 */
    private static final String PLAY_URL_PATH = "/open-api/v1/iot/cameras/{cameraId}/play-url";

    private final ObjectMapper objectMapper = ThirdPartyFarmingHttpSupport.createObjectMapper();

    @Autowired
    private ThirdPartyFarmingProperties properties;

    /** {@inheritDoc} */
    @Override
    public List<OpenCameraDto> fetchAllCameras()
    {
        if (!properties.isEnabled())
        {
            throw new ServiceException("第三方监控同步未启用");
        }
        if ("http".equalsIgnoreCase(properties.getMode()))
        {
            return fetchFromHttp();
        }
        return fetchFromStub();
    }

    /** {@inheritDoc} */
    @Override
    public OpenCameraPlayUrlDto fetchPlayUrl(Long cameraId)
    {
        if (!properties.isEnabled())
        {
            throw new ServiceException("第三方监控服务未启用");
        }
        if (cameraId == null)
        {
            throw new ServiceException("摄像头ID不能为空");
        }
        if ("http".equalsIgnoreCase(properties.getMode()))
        {
            return fetchPlayUrlFromHttp(cameraId);
        }
        return fetchPlayUrlFromStub(cameraId);
    }

    /** stub 模式：读取 classpath 监控列表 JSON 数组 */
    private List<OpenCameraDto> fetchFromStub()
    {
        try
        {
            ClassPathResource resource = new ClassPathResource(STUB_RESOURCE);
            if (!resource.exists())
            {
                return Collections.emptyList();
            }
            try (InputStream in = resource.getInputStream())
            {
                String json = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
                return objectMapper.readValue(json, new TypeReference<List<OpenCameraDto>>()
                {
                });
            }
        }
        catch (ServiceException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceException("读取第三方监控样例失败：" + e.getMessage());
        }
    }

    /** http 模式：按 pageNum 递增分页直至 records 不足 pageSize 或已达 total */
    private List<OpenCameraDto> fetchFromHttp()
    {
        ThirdPartyFarmingHttpSupport.requireBaseUrl(properties, "第三方生产管理系统 base-url 未配置");
        RestTemplate restTemplate = ThirdPartyFarmingHttpSupport.createRestTemplate(properties);
        HttpHeaders headers = ThirdPartyFarmingHttpSupport.buildOpenApiHeaders(properties);
        List<OpenCameraDto> all = new ArrayList<>();
        int pageNum = 1;
        int pageSize = Math.min(Math.max(properties.getPageSize(), 1), 200);
        Long total = null;
        while (true)
        {
            String url = UriComponentsBuilder.fromHttpUrl(ThirdPartyFarmingHttpSupport.resolveUrl(properties, LIST_PATH))
                    .queryParam("pageNum", pageNum)
                    .queryParam("pageSize", pageSize)
                    .toUriString();
            try
            {
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
                        new HttpEntity<>(headers), String.class);
                if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null)
                {
                    throw new ServiceException("第三方监控接口返回异常");
                }
                OpenApiResponse<OpenApiPageResult<OpenCameraDto>> body = objectMapper.readValue(response.getBody(),
                        new TypeReference<OpenApiResponse<OpenApiPageResult<OpenCameraDto>>>()
                        {
                        });
                if (body == null || body.getCode() == null || body.getCode() != 0)
                {
                    String msg = body != null && StringUtils.hasText(body.getMessage()) ? body.getMessage() : "业务失败";
                    throw new ServiceException("第三方监控接口：" + msg);
                }
                OpenApiPageResult<OpenCameraDto> page = body.getData();
                if (page == null || CollectionUtils.isEmpty(page.getRecords()))
                {
                    break;
                }
                all.addAll(page.getRecords());
                if (total == null && page.getTotal() != null)
                {
                    total = page.getTotal();
                }
                if (page.getRecords().size() < pageSize)
                {
                    break;
                }
                if (total != null && all.size() >= total)
                {
                    break;
                }
                pageNum++;
            }
            catch (ServiceException e)
            {
                throw e;
            }
            catch (RestClientException e)
            {
                throw new ServiceException("第三方服务不可用：" + e.getMessage());
            }
            catch (Exception e)
            {
                throw new ServiceException("解析第三方监控数据失败：" + e.getMessage());
            }
        }
        return all;
    }

    /** stub 模式：在 stub-camera-play-urls.json 中按 cameraId 匹配 */
    private OpenCameraPlayUrlDto fetchPlayUrlFromStub(Long cameraId)
    {
        try
        {
            ClassPathResource resource = new ClassPathResource(STUB_PLAY_URL_RESOURCE);
            if (!resource.exists())
            {
                throw new ServiceException("未配置播放地址样例数据");
            }
            try (InputStream in = resource.getInputStream())
            {
                String json = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
                List<OpenCameraPlayUrlDto> list = objectMapper.readValue(json,
                        new TypeReference<List<OpenCameraPlayUrlDto>>()
                        {
                        });
                if (list == null)
                {
                    throw new ServiceException("播放地址样例为空");
                }
                for (OpenCameraPlayUrlDto item : list)
                {
                    if (item != null && cameraId.equals(item.getCameraId()))
                    {
                        return item;
                    }
                }
                throw new ServiceException("未找到摄像头 " + cameraId + " 的播放地址样例");
            }
        }
        catch (ServiceException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceException("读取第三方播放地址样例失败：" + e.getMessage());
        }
    }

    /** http 模式：GET play-url，校验 code=0 且 videoUrl 非空 */
    private OpenCameraPlayUrlDto fetchPlayUrlFromHttp(Long cameraId)
    {
        ThirdPartyFarmingHttpSupport.requireBaseUrl(properties, "第三方生产管理系统 base-url 未配置");
        RestTemplate restTemplate = ThirdPartyFarmingHttpSupport.createRestTemplate(properties);
        HttpHeaders headers = ThirdPartyFarmingHttpSupport.buildOpenApiHeaders(properties);
        String url = ThirdPartyFarmingHttpSupport.resolveUrl(properties,
                PLAY_URL_PATH.replace("{cameraId}", String.valueOf(cameraId)));
        try
        {
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
                    new HttpEntity<>(headers), String.class);
            if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null)
            {
                throw new ServiceException("第三方播放地址接口返回异常");
            }
            OpenApiResponse<OpenCameraPlayUrlDto> body = objectMapper.readValue(response.getBody(),
                    new TypeReference<OpenApiResponse<OpenCameraPlayUrlDto>>()
                    {
                    });
            if (body == null || body.getCode() == null || body.getCode() != 0)
            {
                String msg = body != null && StringUtils.hasText(body.getMessage()) ? body.getMessage() : "业务失败";
                throw new ServiceException("第三方播放地址接口：" + msg);
            }
            OpenCameraPlayUrlDto data = body.getData();
            if (data == null || !StringUtils.hasText(data.getVideoUrl()))
            {
                throw new ServiceException(LivestockMonitorSyncRules.MSG_VIDEO_URL_REQUIRED);
            }
            return data;
        }
        catch (ServiceException e)
        {
            throw e;
        }
        catch (RestClientException e)
        {
            throw new ServiceException("第三方服务不可用：" + e.getMessage());
        }
        catch (Exception e)
        {
            throw new ServiceException("解析第三方播放地址失败：" + e.getMessage());
        }
    }
}
