# network/downloader.py
import os
import json
import re
import shutil
import urllib.request
import urllib.error
from pathlib import Path
from urllib.parse import urlparse


def build_sfx_filename(display_name, file_hash, file_url):
    """
    构造 sfx 缓存文件名
    格式: ${safeName}_${fileHash}${ext}
    """
    # 1. 清理非法字符
    safe_name = re.sub(r'[\\/:*?"<>|]', "_", display_name)

    # 2. 提取扩展名
    ext = ""
    try:
        parsed = urlparse(file_url)
        ext = "".join(Path(parsed.path).suffixes)
    except Exception:
        pass

    if not ext:
        ext = ".mp3"  # 默认扩展名

    # 3. 构造最终文件名
    return f"{safe_name}_{file_hash}{ext}"


def extract_file_hash_from_filename(filename):
    """
    从文件名中提取 fileHash
    匹配模式: name_hash.ext
    """
    match = re.search(r"_([a-f0-9]{8,64})\.[^.]+$", filename, re.IGNORECASE)
    return match.group(1) if match else None


def filename_matches_hash(filename, file_hash):
    """
    检查文件名是否匹配指定的 fileHash
    """
    extracted = extract_file_hash_from_filename(filename)
    return extracted == file_hash


def download_remote_file_handler(payload_str, data_cache_dir):
    payload = json.loads(payload_str)
    file_url = payload.get("file_url", "")
    display_name = payload.get("display_name", "")
    file_hash = payload.get("file_hash", "")
    token = payload.get("token", "")

    if not file_url or not display_name or not file_hash:
        raise ValueError("Missing required fields: file_url, display_name or file_hash")

    # 1. 确保缓存目录存在
    download_dir = os.path.join(data_cache_dir, "sfx_downloads")
    os.makedirs(download_dir, exist_ok=True)

    try:
        req = urllib.request.Request(file_url)
        # 2. 如果有 Token，则添加到 Header
        if token and token.strip():
            req.add_header("Authorization", f"Bearer {token}")

        with urllib.request.urlopen(req, timeout=30) as response:
            final_url = response.geturl()
            # 使用工具函数构造文件名
            filename = build_sfx_filename(display_name, file_hash, final_url)

            local_path = os.path.join(download_dir, filename)
            # 3. 执行下载（如果本地不存在）
            if not os.path.exists(local_path):
                with open(local_path, "wb") as out_file:
                    shutil.copyfileobj(response, out_file)
    except Exception as e:
        raise RuntimeError(f"Failed to download {file_url}: {e}")

    result = {"path": local_path.replace("\\", "/"), "filename": filename}
    return json.dumps(result)


def download_json_handler(payload_str, data_cache_dir):
    payload = json.loads(payload_str)
    remote_url = payload.get("url", "")
    token = payload.get("token", "")

    req = urllib.request.Request(remote_url)
    # 2. 如果有 Token，则添加到 Header
    if token and token.strip():
        req.add_header("Authorization", f"Bearer {token}")

    try:
        # 3. 发送请求
        with urllib.request.urlopen(req, timeout=30) as response:
            raw_data = response.read().decode("utf-8")
            # 验证是否为合法 JSON
            data = json.loads(raw_data)
            # 返回标准的 JSON 字符串给 Electron 捕获
            return json.dumps(data)

    except urllib.error.HTTPError as e:
        try:
            # 这里的 e.fp 指向错误响应的内容流
            error_body = e.fp.read().decode("utf-8")
            cloud_error_data = json.loads(error_body)

            # 如果后端返回了 { "message": "...", "status": ...}
            return json.dumps(
                {
                    "status": e.code,
                    "success": False,
                    "needAuth": cloud_error_data.get("needAuth", False),
                    "message": cloud_error_data.get("message", "请求失败"),
                    "cloud_data": cloud_error_data,
                }
            )
        except Exception:
            # 如果后端没返回 JSON 格式的错误，则回退到基础错误
            return json.dumps(
                {
                    "status": e.code,
                    "error": str(e),
                    "success": False,
                    "message": f"HTTP错误: {e.code}",
                }
            )

    except Exception as e:
        # 其他网络异常
        return json.dumps({"status": 500, "error": str(e), "success": False})
