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

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.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;

/**
 * 第三方养殖开放接口<strong>分页拉取</strong>共用逻辑。
 * <p>
 * 开放接口统一返回 {@link OpenApiResponse}{@code <}{@link OpenApiPageResult}{@code <T>>}，
 * 本类负责循环 {@code pageNum=1..N} 直至 records 为空或已达 total。
 * </p>
 *
 * <h3>分页终止条件（满足任一即停止）</h3>
 * <ul>
 *   <li>当前页 records 为空</li>
 *   <li>当前页条数 &lt; pageSize</li>
 *   <li>已收集条数 &gt;= total</li>
 * </ul>
 *
 * <h3>Stub 模式</h3>
 * <p>
 * {@link #fetchFromStub} 从 classpath JSON 读取全量列表，供 {@code third-party.farming.mode=stub} 联调。
 * </p>
 */
public final class ThirdPartyFarmingPageFetcher
{
    private ThirdPartyFarmingPageFetcher()
    {
    }

    /**
     * HTTP 模式：分页拉取直至全量。
     *
     * @param listPath   开放接口路径，如 {@code /open-api/v1/farming/enclosures}
     * @param responseType Jackson 泛型类型引用
     * @param apiLabel   异常消息中的接口中文名
     */
    public static <T> List<T> fetchAllPages(ThirdPartyFarmingProperties properties, ObjectMapper objectMapper,
            String listPath, TypeReference<OpenApiResponse<OpenApiPageResult<T>>> responseType, String apiLabel)
    {
        return fetchAllPages(properties, objectMapper, listPath, responseType, apiLabel, null);
    }

    /**
     * HTTP 模式：分页拉取，可附加增量查询参数（如 {@code updatedAfter}、{@code startTime}、{@code endTime}）。
     */
    public static <T> List<T> fetchAllPages(ThirdPartyFarmingProperties properties, ObjectMapper objectMapper,
            String listPath, TypeReference<OpenApiResponse<OpenApiPageResult<T>>> responseType, String apiLabel,
            Map<String, String> extraQueryParams)
    {
        ThirdPartyFarmingHttpSupport.requireBaseUrl(properties, "第三方生产管理系统 base-url 未配置");
        RestTemplate restTemplate = ThirdPartyFarmingHttpSupport.createRestTemplate(properties);
        HttpHeaders headers = ThirdPartyFarmingHttpSupport.buildOpenApiHeaders(properties);
        List<T> all = new ArrayList<>();
        int pageNum = 1;
        // 接口上限 200，配置超出时截断
        int pageSize = Math.min(Math.max(properties.getPageSize(), 1), 200);
        Long total = null;
        while (true)
        {
            String urlBuilder = ThirdPartyFarmingHttpSupport.resolveUrl(properties, listPath);
            UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(urlBuilder)
                    .queryParam("pageNum", pageNum)
                    .queryParam("pageSize", pageSize);
            if (extraQueryParams != null)
            {
                for (Map.Entry<String, String> entry : extraQueryParams.entrySet())
                {
                    if (StringUtils.hasText(entry.getKey()) && StringUtils.hasText(entry.getValue()))
                    {
                        uriBuilder.queryParam(entry.getKey(), entry.getValue());
                    }
                }
            }
            String url = uriBuilder.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(apiLabel + "接口返回异常");
                }
                OpenApiResponse<OpenApiPageResult<T>> body = objectMapper.readValue(response.getBody(), responseType);
                // code=0 表示业务成功；401 鉴权失败；500 服务端错误
                if (body == null || body.getCode() == null || body.getCode() != 0)
                {
                    String msg = body != null && StringUtils.hasText(body.getMessage()) ? body.getMessage() : "业务失败";
                    throw new ServiceException(apiLabel + "接口：" + msg);
                }
                OpenApiPageResult<T> 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("解析" + apiLabel + "数据失败：" + e.getMessage());
            }
        }
        return all;
    }

    /**
     * Stub 模式：读取 classpath 样例 JSON 数组。
     */
    public static <T> List<T> fetchFromStub(ObjectMapper objectMapper, String stubResource,
            TypeReference<List<T>> listType, String apiLabel)
    {
        try
        {
            ClassPathResource resource = new ClassPathResource(stubResource);
            if (!resource.exists())
            {
                return Collections.emptyList();
            }
            try (InputStream in = resource.getInputStream())
            {
                String json = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
                return objectMapper.readValue(json, listType);
            }
        }
        catch (ServiceException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceException("读取" + apiLabel + "样例失败：" + e.getMessage());
        }
    }
}
