from __future__ import annotations

from typing import Optional

from .._http import HttpClient
from .._environment import Environment, resolve_platform_url
from ..models.peptide import (
    PeptideJobSubmission,
    PeptideJob,
    PeptideJobStatus,
    PeptideResults,
    PeptideDetail,
    PeptideSummary,
    PeptideDownsyncResult,
)


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

    def _url(self, environment: Environment) -> str | None:
        return resolve_platform_url(environment)

    # ── de novo peptide generation ───────────────────────────────

    def submit_design(
        self,
        project: str,
        job_name: str,
        protein_file_name: str,
        coordinates: list[float],
        peptide_length: Optional[int] = None,
        ref_ligand_name: Optional[str] = None,
        radius: int = 20,
        num_peptides: int = 100,
        environment: Environment = None,
    ) -> PeptideJobSubmission:
        payload: dict = {
            "job_name": job_name,
            "protein_file_name": protein_file_name,
            "coordinates": coordinates,
            "radius": radius,
            "num_peptides": num_peptides,
        }
        if peptide_length is not None:
            payload["peptide_length"] = peptide_length
        if ref_ligand_name is not None:
            payload["ref_ligand_name"] = ref_ligand_name
        data = self._http.post(
            "/peptide-design/submit",
            json=payload,
            base_url=self._url(environment),
        )
        return PeptideJobSubmission.from_dict(data)

    # ── peptide docking ──────────────────────────────────────────

    def submit_docking(
        self,
        project: str,
        job_name: str,
        protein_file_name: str,
        peptide_pdb_name: Optional[str] = None,
        peptide_sequence: Optional[str] = None,
        coordinates: Optional[list[float]] = None,
        ref_ligand_name: Optional[str] = None,
        radius: int = 20,
        num_peptides: int = 100,
        noise_mode: str = "free",
        environment: Environment = None,
    ) -> PeptideJobSubmission:
        payload: dict = {
            "job_name": job_name,
            "protein_file_name": protein_file_name,
            "radius": radius,
            "num_peptides": num_peptides,
            "noise_mode": noise_mode,
        }
        if peptide_pdb_name is not None:
            payload["peptide_pdb_name"] = peptide_pdb_name
        if peptide_sequence is not None:
            payload["peptide_sequence"] = peptide_sequence
        if coordinates is not None:
            payload["coordinates"] = coordinates
        if ref_ligand_name is not None:
            payload["ref_ligand_name"] = ref_ligand_name
        data = self._http.post(
            "/peptide-design/dock",
            json=payload,
            base_url=self._url(environment),
        )
        return PeptideJobSubmission.from_dict(data)

    # ── job listing & status ─────────────────────────────────────

    def list_jobs(
        self,
        project: str,
        job_name: Optional[str] = None,
        design_mode: Optional[str] = None,
        environment: Environment = None,
    ) -> list[PeptideJob]:
        params: dict = {}
        if job_name:
            params["job_name"] = job_name
        if design_mode:
            params["design_mode"] = design_mode
        data = self._http.get(
            "/peptide-design/jobs",
            params=params or None,
            base_url=self._url(environment),
        )
        return [PeptideJob.from_dict(j) for j in data.get("jobs", [])]

    def get_status(
        self,
        project: str,
        job_name: str,
        protein_file_name: str,
        design_mode: Optional[str] = None,
        environment: Environment = None,
    ) -> PeptideJobStatus:
        params: dict = {}
        if design_mode:
            params["design_mode"] = design_mode
        data = self._http.get(
            f"/peptide-design/status/{job_name}/{protein_file_name}",
            params=params or None,
            base_url=self._url(environment),
        )
        return PeptideJobStatus.from_dict(data)

    # ── results ──────────────────────────────────────────────────

    def get_results(
        self,
        project: str,
        job_name: str,
        protein_file_name: str,
        peptide_job_id: Optional[str] = None,
        limit: int = 50,
        offset: int = 0,
        sort_by: str = "confidence_score",
        sort_order: str = "desc",
        environment: Environment = None,
    ) -> PeptideResults:
        params: dict = {
            "limit": limit,
            "offset": offset,
            "sort_by": sort_by,
            "sort_order": sort_order,
        }
        if peptide_job_id:
            params["peptide_job_id"] = peptide_job_id
        data = self._http.get(
            f"/peptide-design/results/{job_name}/{protein_file_name}",
            params=params,
            base_url=self._url(environment),
        )
        return PeptideResults.from_dict(data)

    def get_peptide(
        self,
        project: str,
        peptide_id: str,
        environment: Environment = None,
    ) -> PeptideDetail:
        data = self._http.get(
            f"/peptide-design/peptide/{peptide_id}",
            base_url=self._url(environment),
        )
        return PeptideDetail.from_dict(data)

    def get_summary(
        self,
        project: str,
        job_name: str,
        protein_file_name: str,
        environment: Environment = None,
    ) -> PeptideSummary:
        data = self._http.get(
            f"/peptide-design/summary/{job_name}/{protein_file_name}",
            base_url=self._url(environment),
        )
        return PeptideSummary.from_dict(data)

    # ── downsync ─────────────────────────────────────────────────

    def downsync(
        self,
        project: str,
        job_name: str,
        environment: Environment = None,
    ) -> PeptideDownsyncResult:
        data = self._http.post(
            f"/peptide-design/downsync/{job_name}",
            json={},
            base_url=self._url(environment),
        )
        return PeptideDownsyncResult.from_dict(data)
