package edu.whut.smilepicturebackend.manager.upload;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import edu.whut.smilepicturebackend.exception.BusinessException;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import edu.whut.smilepicturebackend.exception.ThrowUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

/**
 * URL 图片上传
 */
@Service
@Slf4j
public class UrlPictureUpload extends PictureUploadTemplate {

    @Override
    protected void validPicture(Object inputSource) {
        String fileUrl = (String) inputSource;
        // 1. 校验非空
        ThrowUtils.throwIf(StrUtil.isBlank(fileUrl), ErrorCode.PARAMS_ERROR, "文件地址为空");

        // 2. 校验 URL 格式
        try {
            new URL(fileUrl);
        } catch (MalformedURLException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件地址格式不正确");
        }
        // 3. 校验 URL 的协议
        ThrowUtils.throwIf(!fileUrl.startsWith("http://") && !fileUrl.startsWith("https://"),
                ErrorCode.PARAMS_ERROR, "仅支持 HTTP 或 HTTPS 协议的文件地址"
        );
    }

    /**
     * 只发一次 HEAD，就做远程校验 + 提取扩展名
     * @return 不含点的扩展名，比如 "jpg","png"，取不出时返回空串
     */
    protected String fetchAndValidateExtension(String fileUrl) {
        log.info("收到的fileurl:{}",fileUrl);
        try (HttpResponse resp = HttpUtil
                .createRequest(Method.HEAD, fileUrl)
                .execute()) {
            if (resp.getStatus() != HttpStatus.HTTP_OK) {
                // 网络或权限问题时直接降级
                log.warn("HEAD 请求未返回 200，status = {}，将从 URL 中提取后缀", resp.getStatus());
                return "";
            }
            // 1) Content-Type 验证 & 提取扩展名
            String ct = resp.header("Content-Type");
            String ext = "";
            if (StrUtil.isNotBlank(ct) && ct.contains("/")) {
                // e.g. "image/jpeg"
                String raw = StrUtil.subAfter(ct, "/", true).toLowerCase();
                ext = raw.equals("jpeg") ? "jpg" : raw;
                // 验证白名单
                List<String> allow = Arrays.asList(
                        "image/jpeg", "image/jpg", "image/png", "image/webp"
                );
                ThrowUtils.throwIf(
                        !allow.contains(ct.toLowerCase()),
                        ErrorCode.PARAMS_ERROR,
                        "不支持的图片类型：" + ct
                );
            }

            // 2) Content-Length 验证
            String len = resp.header("Content-Length");
            if (StrUtil.isNotBlank(len)) {
                long size = Long.parseLong(len);
                long max = 2L * 1024 * 1024;
                ThrowUtils.throwIf(
                        size > max,
                        ErrorCode.PARAMS_ERROR,
                        "文件大小不能超过 2MB"
                );
            }

            return ext;
        } catch (NumberFormatException e) {
            throw new BusinessException(
                    ErrorCode.PARAMS_ERROR, "文件大小格式异常");
        }
    }


    @Override
    protected String getOriginFilename(Object inputSource) {
        String fileUrl = (String) inputSource;
        // 先把 query string 去掉
        int qIdx = fileUrl.indexOf('?');
        String cleanUrl = qIdx > 0 ? fileUrl.substring(0, qIdx) : fileUrl;

        // 1) 尝试 HEAD 拿扩展名，不可用时 ext == ""
        String ext = fetchAndValidateExtension(cleanUrl);

        // 2) fallback：若 ext 为空，就直接返回去掉参数后的 URL
        if (StrUtil.isBlank(ext)) {
            return cleanUrl;
        } else {
            // 3) 从 cleanUrl 中拿到 baseName，再拼回去
            String base = FileUtil.mainName(FileUtil.getName(cleanUrl));
            return base + "." + ext;
        }
    }

    @Override
    protected void processFile(Object inputSource, File file) throws Exception {
        String fileUrl = (String) inputSource;
        // 下载文件到临时目录
        HttpUtil.downloadFile(fileUrl, file);
    }
}
