import hashlib
import hmac
import os
import time
import urllib.parse

import requests

# 腾讯云 COS 下载签名凭证（与 rpa_step1_get.py 的 SAAS_COS_* 凭证一致；RPA 脚本独立运行一次，不读环境变量，直接固定常量）
COS_SECRET_ID = 'AKIDjGZcOu9BwSikW1HHchW4PaVAYicGeldF'
COS_SECRET_KEY = 'PXWGm24qUszrTpvlLh5E8mAI9m8F7k7E'
COS_BUCKET = 'usaeu-1259285998'
COS_REGION = 'ap-guangzhou'
# 签名下载 URL 有效期（秒）；COS 服务端仅校验"签名与 q-sign-time 一致 + 当前时间在窗口内"
COS_SIGN_EXPIRATION_SECONDS = 600
# 下载超时（秒）
DOWNLOAD_TIMEOUT_SECONDS = 60

FIELDS = ('upload_file_path1', 'upload_file_path2', 'upload_file_path3')


def sign_cos_url(file_url, expiration_seconds=COS_SIGN_EXPIRATION_SECONDS):
    """
    为 COS 相对路径生成带签名的临时下载 URL。
    算法与 qcloud/cos-sdk-v5 Signature::createPresignedUrl 一致（q-sign-algorithm=sha1，
    q-header-list=host、q-url-param-list=空），已在 rpa_step1_get.py 用 SDK 输出逐字符校验过。
    完整 http(s):// URL（source 流程 file.usaeu.com 或已签名 URL）无需签名，原样返回。
    """
    file_url = (file_url or '').strip()
    if not file_url:
        return file_url
    if file_url.lower().startswith(('http://', 'https://')):
        return file_url

    now = int(time.time())
    # q-sign-time 起始提前 60s（与 SDK 相同），结束 = 起始 + 有效期
    sign_time = f'{now - 60};{now - 60 + expiration_seconds}'
    host = f'{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com'
    # 与 SDK encodeKey 相同：rawurlencode 后 %2F 还原为 /
    path = '/' + urllib.parse.quote(file_url.lstrip('/'), safe='/')

    http_string = 'get\n' + urllib.parse.unquote(path) + '\n\n' + 'host=' + host + '\n'
    string_to_sign = ('sha1\n' + sign_time + '\n'
                      + hashlib.sha1(http_string.encode('utf-8')).hexdigest() + '\n')
    sign_key = hmac.new(COS_SECRET_KEY.encode('utf-8'), sign_time.encode('utf-8'),
                        hashlib.sha1).hexdigest()
    signature = hmac.new(sign_key.encode('utf-8'), string_to_sign.encode('utf-8'),
                         hashlib.sha1).hexdigest()

    authorization = (
        'q-sign-algorithm=sha1&q-ak=' + COS_SECRET_ID
        + '&q-sign-time=' + sign_time + '&q-key-time=' + sign_time
        + '&q-header-list=host&q-url-param-list=&q-signature=' + signature
    )
    return 'https://' + host + path + '?sign=' + urllib.parse.quote(authorization, safe='')


def download_one(file_url, local_path):
    """
    下载单个文件到本地路径（自动创建父目录，已存在直接覆盖）。
    返回: dict {'success': bool, 'http_code': int, 'error': str}
    """
    result = {'success': False, 'http_code': None, 'error': None}
    try:
        os.makedirs(os.path.dirname(os.path.abspath(local_path)) or '.', exist_ok=True)
        response = requests.get(file_url, timeout=DOWNLOAD_TIMEOUT_SECONDS, stream=True)
        result['http_code'] = response.status_code
        if response.status_code != 200:
            result['error'] = f"HTTP {response.status_code} {response.reason}"
            print(f"  错误: {result['error']}")
            return result
        with open(local_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    f.write(chunk)
        result['success'] = True
        return result
    except Exception as e:
        result['error'] = str(e)
        print(f"  错误: {e}")
        return result


def download_files(upload_file_path1, upload_file_path2, upload_file_path3,
                   data_source, download_path1, download_path2, download_path3):
    """
    下载注册资料文件：upload_file_path1/2/3 与 download_path1/2/3（含文件名的完整本地路径）一一对应。

    - data_source='api'：upload_file_path* 是 COS 相对路径（私有桶），拼固定域名
      并生成带签名临时下载 URL 后下载；已经是完整 URL 的（如 rpa_step1_get 已签名过的）不重复签名，直接下载。
    - data_source 非 'api'（source 行）：uplaod_file_path* 是完整 URL（file.usaeu.com），直接下载。

    空值跳过对应文件；单个文件失败不阻断其余文件（错误信息完整打印）；
    全部成功时打印三个文件下载到的本地地址。
    返回: dict {'results': [{field, url, saved_to, success, skipped, http_code, error}], 'all_success': bool}
    """
    urls = (upload_file_path1, upload_file_path2, upload_file_path3)
    local_paths = (download_path1, download_path2, download_path3)
    is_api = str(data_source or '').lower() == 'api'

    results = []
    for field, file_url, local_path in zip(FIELDS, urls, local_paths):
        file_url = (file_url or '').strip()
        local_path = (local_path or '').strip()
        item = {'field': field, 'url': file_url, 'saved_to': local_path,
                'success': False, 'skipped': False, 'http_code': None, 'error': None}

        # 地址或本地路径为空：跳过该文件（如无 path3），不报错不阻断
        if not file_url or not local_path:
            item['skipped'] = True
            print(f"[{field}] 地址或本地路径为空，跳过: {file_url!r} -> {local_path!r}")
            results.append(item)
            continue

        # api 行：相对路径 → 前缀 + 签名；完整 URL 原样（source 行一律原样）
        download_url = sign_cos_url(file_url) if is_api else file_url
        item['url'] = download_url
        print(f"[{field}] 下载中: {download_url}")
        one = download_one(download_url, local_path)
        item['success'] = one['success']
        item['http_code'] = one['http_code']
        item['error'] = one['error']
        if one['success']:
            print(f"[{field}] 下载成功: {local_path}")
        else:
            print(f"[{field}] 下载失败: {download_url} -> {local_path}")
        results.append(item)

    all_success = all(r['success'] or r['skipped'] for r in results)
    if all_success:
        print("三个文件已下载到本地:")
        for r in results:
            print(f"  {r['field']} -> {r['saved_to']}")
    else:
        failed = [r['field'] for r in results if not r['success'] and not r['skipped']]
        print(f"下载失败（未全部成功）: {failed}")
    return {'results': results, 'all_success': all_success}
