from __future__ import annotations

import mimetypes
from pathlib import Path
from typing import Optional, Union

from .._http import HttpClient
from .._environment import Environment, resolve_platform_url
from ..models.files import FileInfo, UploadResponse


class FilesNamespace:
    def __init__(self, http: HttpClient):
        self._http = http

    def _url(self, environment: Environment) -> Optional[str]:
        return resolve_platform_url(environment)

    # ── upload ───────────────────────────────────────────────────

    def upload(
        self,
        project: str,
        paths: Union[str, Path, list[Union[str, Path]]],
        folder: str = "upload",
        environment: Environment = None,
    ) -> UploadResponse:
        if isinstance(paths, (str, Path)):
            paths = [paths]

        multipart_files = []
        for p in paths:
            p = Path(p)
            mime = mimetypes.guess_type(str(p))[0] or "application/octet-stream"
            multipart_files.append(("files", (p.name, p.read_bytes(), mime)))

        data = self._http.post_multipart(
            "/uploads",
            data={"job_name": project, "folder": folder},
            files=multipart_files,
            base_url=self._url(environment),
        )
        return UploadResponse.from_dict(data)

    def upload_bytes(
        self,
        project: str,
        filename: str,
        content: bytes,
        folder: str = "upload",
        content_type: str = "application/octet-stream",
        environment: Environment = None,
    ) -> UploadResponse:
        data = self._http.post_multipart(
            "/uploads",
            data={"job_name": project, "folder": folder},
            files=[("files", (filename, content, content_type))],
            base_url=self._url(environment),
        )
        return UploadResponse.from_dict(data)

    # ── list ─────────────────────────────────────────────────────

    def list(
        self,
        project: str,
        folder: str = "upload",
        environment: Environment = None,
    ) -> list[FileInfo]:
        data = self._http.get("/files/list", params={
            "job_name": project,
            "folder": folder,
        }, base_url=self._url(environment))
        return [FileInfo.from_dict(f) for f in data.get("files", [])]

    def list_all(self, project: str, environment: Environment = None) -> list[FileInfo]:
        data = self._http.get(
            "/files/list/all",
            params={"job_name": project},
            base_url=self._url(environment),
        )
        return [FileInfo.from_dict(f) for f in data.get("files", [])]

    def list_by_format(
        self,
        project: str,
        format_type: str,
        environment: Environment = None,
    ) -> list[FileInfo]:
        data = self._http.get("/files/list/format", params={
            "job_name": project,
            "format_type": format_type,
        }, base_url=self._url(environment))
        return [FileInfo.from_dict(f) for f in data.get("files", [])]

    # ── read / download ──────────────────────────────────────────

    def get_content(
        self,
        project: str,
        file_name: str,
        folder: str = "upload",
        environment: Environment = None,
    ) -> str:
        data = self._http.get("/files/content", params={
            "job_name": project,
            "folder": folder,
            "file_name": file_name,
        }, base_url=self._url(environment))
        return data.get("content", "")

    def download(
        self,
        project: str,
        file_name: str,
        folder: str = "upload",
        environment: Environment = None,
    ) -> bytes:
        response = self._http.get_raw("/files/download", params={
            "job_name": project,
            "folder": folder,
            "file_name": file_name,
        }, base_url=self._url(environment))
        return response.content

    def download_to(
        self,
        project: str,
        file_name: str,
        dest: Union[str, Path],
        folder: str = "upload",
        environment: Environment = None,
    ) -> Path:
        dest = Path(dest)
        if dest.is_dir():
            dest = dest / file_name
        dest.write_bytes(self.download(project, file_name, folder, environment))
        return dest

    # ── metadata ─────────────────────────────────────────────────

    def get_metadata(
        self,
        project: str,
        file_name: str,
        folder: str = "upload",
        environment: Environment = None,
    ) -> FileInfo:
        data = self._http.get("/files/metadata", params={
            "job_name": project,
            "folder": folder,
            "file_name": file_name,
        }, base_url=self._url(environment))
        return FileInfo.from_dict(data)

    def update_metadata(
        self,
        project: str,
        file_name: str,
        metadata: dict,
        folder: str = "upload",
        environment: Environment = None,
    ) -> dict:
        return self._http.patch("/files/metadata", json={
            "job_name": project,
            "folder": folder,
            "file_name": file_name,
            "metadata": metadata,
        }, base_url=self._url(environment))

