import logging

import httpx

from .._utils import cuid
from ..config import settings

logger = logging.getLogger(__name__)


class HttpClient:
    def __init__(self, api_key: str = ""):
        self.http_client = httpx.Client(
            base_url=settings.base_url,
            headers={"X-API-KEY": api_key},
            timeout=settings.timeout,
        )

    def check_user(
        self,
        api_key: str | None = None,
    ) -> dict:
        """
        检查当前 API Key 对应的用户信息

        Parameters
        ----------
        api_key: API Key，若不传则使用 settings.api_key
        """
        resolved_api_key = (api_key or settings.api_key or "").strip()
        if not resolved_api_key:
            raise ValueError("🙄 无 API Key")

        self.http_client.headers.update({"X-API-KEY": resolved_api_key})

        try:
            response = self.http_client.get("/user/me")
            response.raise_for_status()
            result = response.json()
        except Exception as e:
            raise ValueError(
                f"🙄 获取用户信息失败，请检查 API Key 或网络: {e}"
            ) from None

        user_info = {
            "username": result["username"],
            "user_id": result["cuid"],
            "api_key": resolved_api_key,
            "created_at": result["createdAt"],
        }

        settings.api_key = resolved_api_key

        return user_info

    def list_models(self):
        """
        获取可用的模型列表

        Returns
        -------
        返回一个列表，例如：['Qwen/Qwen2.5-3B']
        """
        try:
            response = self.http_client.get("/runner/models")
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取模型列表失败，请检查网络: {e}") from None

    def create_task(
        self,
        task_type: str,
        run_id: str,
        model: str,
        user_id: str,
        task_id: str = cuid(12),
        runner_version: str = "",
        lora: dict | None = None,
    ) -> dict:
        """
        创建一个训练/推理任务

        Parameters
        ----------
        task_type: 任务类型，可选 TRAIN/SAMPLE
        run_id: 运行会话 id，上层连接传递
        model: 选择的模型
        user_id: 用户 id
        task_id: 任务 id，12位随机字符串
        runner_version: 可以指定运行器版本，如果不指定则随机选择一个
        lora: 创建 Lora 模型的配置

        Returns
        -------
        返回任务的信息，例如：
        {
          "cuid": "d9pmrwsl6",
          "model": "Qwen/Qwen2.5-3B",
          "runId": "IsE90fZsKoqipqyzAAAB",
          "runnerId": "d9pmrwsle3",
          "type": "TRAIN",
          "userId": "ubrmy3jg21"
        }
        其中 `cuid` 为任务的唯一 id, runnerId 是为任务分配的运行器 id
        """
        try:
            response = self.http_client.post(
                "/runner/assign_task",
                json={
                    "cuid": task_id,  # 随机生成一个 12 位字符串
                    "type": task_type,
                    "model": model,
                    "runId": run_id,
                    "lora": lora,
                    "sdkVersion": settings.version,
                    "runnerVersion": runner_version,
                    "userId": user_id,
                },
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 创建 {task_type} 任务失败，请检查网络: {e}") from None

    def list_weights(self, user_id: str, page=1, page_size=20) -> dict:
        """
        列出模型列表，只包含权重

        Parameters
        ----------
        user_id: 用户 id
        page: 当前所在页，默认为 1
        page_size: 每页的数量，默认为 20

        Returns
        -------
        ```
        {
          "data": [
            {
              "createdAt": "Tue, 23 Dec 2025 11:15:38 GMT",
              "cuid": "hello",
              "id": 1,
              "path": "/hello",
              "runId": "oI5YMIU13MQM-y0MAAAB",
              "runnerId": "d9pmrwslew",
              "status": "ON",
              "taskId": "d9pmrwsle1",
              "type": "SAMPLE",
              "updatedAt": "Tue, 23 Dec 2025 11:15:40 GMT",
              "userId": "ubrmy3jg21"
            }
          ],
          "pagination": {
            "has_next": false,
            "has_prev": false,
            "page": 1,
            "page_size": 20,
            "total": 2,
            "total_pages": 1
          }
        }
        ```
        """
        try:
            response = self.http_client.get(
                f"/user/{user_id}/weights",
                params={
                    "page": page,
                    "page_size": page_size,
                },
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取模型列表失败，请检查网络: {e}") from None

    def get_archive_url(self, user_id: str, checkpoint_id: str) -> dict[str, str]:
        """
        获取模型权重的临时访问链接

        Parameters
        ----------
        user_id: 用户 id
        checkpoint_id: 存储文件的 id

        Returns
        -------
        ```
        {
          "url": "https://for-nano-tinker-1332237456.cos.ap-beijing.myqcloud.com/models/0a8985p9rq/1pz1nwvyvea5/weights/test001.zip?q-sign-algorithm=sha1&q-ak=AKIDW29B3nMn36wZ2LSRHwOceVCk5IK9lDVc&q-sign-time=1766581973%3B1766582333&q-key-time=1766581973%3B1766582333&q-header-list=host&q-url-param-list=&q-signature=967e3ce4dfac34ad4f1051e20d133f6dc2bf0a86"
        }
        ```
        """
        try:
            response = self.http_client.get(
                f"/user/{user_id}/archive_url/{checkpoint_id}"
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取模型文件失败，请检查网络: {e}") from None

    def get_training_run(self, training_run_id: str) -> dict:
        """
        获取指定训练运行的详细信息

        Parameters
        ----------
        training_run_id: 训练运行 id

        Returns
        -------
        ```
        {
          "training_run_id": "task_test_003",
          "base_model": "Qwen/Qwen3-8B-Base",
          "is_lora": true,
          "lora_rank": 32
        }
        ```

        """
        try:
            response = self.http_client.get(f"/api/runs/{training_run_id}")
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取训练运行详情失败，请检查网络: {e}") from None

    def list_training_runs(self, limit: int = 20, offset: int = 0) -> dict:
        """
        分页列出当前用户的训练运行

        Parameters
        ----------
        limit: 返回条数，默认为 20
        offset: 偏移量，默认为 0

        Returns
        -------
        ```
        {
          "training_runs": [
            {
              "training_run_id": "task_test_003",
              "base_model": "Qwen/Qwen3-8B-Base",
              "is_lora": true
            }
          ],
          "total": 1,
          "limit": 20,
          "offset": 0,
          "has_more": false
        }
        ```

        """
        try:
            response = self.http_client.get(
                "/api/runs",
                params={"limit": limit, "offset": offset},
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取训练运行列表失败，请检查网络: {e}") from None

    def list_checkpoints(self, training_run_id: str) -> dict:
        """
        列出指定训练运行下的检查点列表

        Parameters
        ----------
        training_run_id: 训练运行 id

        Returns
        -------
        ```
        {
          "checkpoints": [
            {
              "checkpoint_id": "hc6tmfpsvz",
              "checkpoint_type": "sampler",
              "time": "2026-03-11T06:56:11.475000Z",
              "path": "/path/to/model_weights.safetensors",
              "size_bytes": 1024000
            }
          ]
        }
        ```

        """
        try:
            response = self.http_client.get(f"/api/runs/{training_run_id}/checkpoints")
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取检查点列表失败，请检查网络: {e}") from None

    def get_checkpoint_archive_url(
        self, training_run_id: str, checkpoint_id: str
    ) -> dict:
        """
        获取指定检查点的临时下载链接

        Parameters
        ----------
        training_run_id: 训练运行 id
        checkpoint_id: 检查点 id

        Returns
        -------
        ```
        {
          "url": "https://example.com/archive.zip",
          "expires": "2026-03-11T10:00:00Z"
        }
        ```

        """
        try:
            response = self.http_client.get(
                f"/api/runs/{training_run_id}/checkpoints/{checkpoint_id}/archive"
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取检查点下载链接失败，请检查网络: {e}") from None

    def delete_checkpoint(self, training_run_id: str, checkpoint_id: str) -> None:
        """
        删除指定训练运行下的检查点

        Parameters
        ----------
        training_run_id: 训练运行 id
        checkpoint_id: 检查点 id

        Returns
        -------
        无返回值，删除成功时返回 None。

        """
        try:
            response = self.http_client.delete(
                f"/api/runs/{training_run_id}/checkpoints/{checkpoint_id}"
            )
            response.raise_for_status()
            return None
        except Exception as e:
            raise ValueError(f"🙄 删除检查点失败，请检查网络: {e}") from None

    def list_user_checkpoints(self, limit: int = 100, offset: int = 0) -> dict:
        """
        分页列出当前用户的所有检查点

        Parameters
        ----------
        limit: 返回条数，默认为 100
        offset: 偏移量，默认为 0

        Returns
        -------
        ```
        {
          "checkpoints": [
            {
              "checkpoint_id": "hc6tmfpsvz",
              "checkpoint_type": "sampler",
              "time": "2026-03-11T06:56:11.475000Z",
              "path": "/path/to/model_weights.safetensors",
              "size_bytes": 1024000
            }
          ],
          "total": 2,
          "limit": 100,
          "offset": 0,
          "has_more": false
        }
        ```

        """
        try:
            response = self.http_client.get(
                "/api/user/checkpoints",
                params={"limit": limit, "offset": offset},
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取用户检查点列表失败，请检查网络: {e}") from None

    def get_session(self, session_id: str) -> dict:
        """
        获取指定会话的信息

        Parameters
        ----------
        session_id: 会话 id

        Returns
        -------
        ```
        {
          "training_run_ids": ["task_test_002", "task_test_003", "task_test_004"],
          "sampler_ids": ["task_test_01"]
        }
        ```

        """
        try:
            response = self.http_client.get(f"/api/sessions/{session_id}")
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取会话信息失败，请检查网络: {e}") from None

    def list_sessions(self, limit: int = 20, offset: int = 0) -> dict:
        """
        分页列出当前用户的所有会话

        Parameters
        ----------
        limit: 返回条数，默认为 20
        offset: 偏移量，默认为 0

        Returns
        -------
        ```
        {
          "sessions": [
            "w12kso9m6em8",
            "iso98x2g25c1",
            "jvmkrcq2did6"
          ]
        }
        ```

        """
        try:
            response = self.http_client.get(
                "/api/sessions",
                params={"limit": limit, "offset": offset},
            )
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取会话列表失败，请检查网络: {e}") from None

    def get_sampler(self, sampler_id: str) -> dict:
        """
        获取指定采样器的信息

        Parameters
        ----------
        sampler_id: 采样器 id

        Returns
        -------
        ```
        {
          "sampler_id": "sampler_test_001",
          "base_model": "Qwen/Qwen3-8B-Base",
          "model_path": "83y7lbpduv/task_test_003/weights/step_100"
        }
        ```

        """
        try:
            response = self.http_client.get(f"/api/samplers/{sampler_id}")
            response.raise_for_status()
            return response.json()
        except Exception as e:
            raise ValueError(f"🙄 获取采样器信息失败，请检查网络: {e}") from None
