use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

use crate::env::container::ContainerInfo;
use crate::env::ports::PortAllocation;
use crate::env::resources::ResourceUsage;
use crate::ship::pr::{CiStatus, PrStatus};

/// Lifecycle of a worktree: ephemeral (auto-GC'd) or permanent (never auto-deleted).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Lifecycle {
    Ephemeral,
    Permanent,
}

/// Runtime status of a worktree's session.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum WorktreeStatus {
    #[default]
    Idle,
    Running,
    Waiting,
    Done,
    Shipping,
}

/// A managed worktree with its metadata.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Worktree {
    pub name: String,
    pub path: PathBuf,
    pub branch: String,
    pub base_branch: String,
    pub base_commit: String,
    pub lifecycle: Lifecycle,
    pub created_at: DateTime<Utc>,
    #[serde(default)]
    pub last_session_id: Option<String>,
    #[serde(default)]
    pub tmux_pane: Option<String>,
    #[serde(default)]
    pub status: WorktreeStatus,
    /// PR number on GitHub (if a PR has been created).
    #[serde(default)]
    pub pr_number: Option<u64>,
    /// PR URL on GitHub.
    #[serde(default)]
    pub pr_url: Option<String>,
    /// Current PR status (draft/open/approved/merged/closed).
    #[serde(default)]
    pub pr_status: PrStatus,
    /// Current CI/GitHub Actions status.
    #[serde(default)]
    pub ci_status: CiStatus,
    /// Container information (if running in a container).
    #[serde(default)]
    pub container: Option<ContainerInfo>,
    /// Port allocation for this worktree.
    #[serde(default)]
    pub ports: Option<PortAllocation>,
    /// Resource usage snapshot (disk, CPU, memory).
    #[serde(default)]
    pub resource_usage: Option<ResourceUsage>,
    /// Task title (from dispatch prompt or imported issue title).
    /// Used as PR title when creating pull requests.
    #[serde(default)]
    pub task_title: Option<String>,
    /// Task description (from imported issue body or user-provided context).
    /// Used in PR body when creating pull requests.
    #[serde(default)]
    pub task_description: Option<String>,
    /// If set, this worktree lives on a remote host (value is the host name).
    #[serde(default)]
    pub remote_host: Option<String>,
    /// Path on the remote host (absolute).
    #[serde(default)]
    pub remote_path: Option<String>,
}

impl Worktree {
    pub fn new(
        name: String,
        path: PathBuf,
        branch: String,
        base_branch: String,
        base_commit: String,
        lifecycle: Lifecycle,
    ) -> Self {
        Self {
            name,
            path,
            branch,
            base_branch,
            base_commit,
            lifecycle,
            created_at: Utc::now(),
            last_session_id: None,
            tmux_pane: None,
            status: WorktreeStatus::Idle,
            pr_number: None,
            pr_url: None,
            pr_status: PrStatus::None,
            ci_status: CiStatus::None,
            container: None,
            ports: None,
            resource_usage: None,
            task_title: None,
            task_description: None,
            remote_host: None,
            remote_path: None,
        }
    }

    /// Create a new worktree that lives on a remote host.
    #[allow(clippy::too_many_arguments)]
    pub fn new_remote(
        name: String,
        path: PathBuf,
        branch: String,
        base_branch: String,
        base_commit: String,
        lifecycle: Lifecycle,
        remote_host: String,
        remote_path: String,
    ) -> Self {
        let mut wt = Self::new(name, path, branch, base_branch, base_commit, lifecycle);
        wt.remote_host = Some(remote_host);
        wt.remote_path = Some(remote_path);
        wt
    }

    pub fn is_ephemeral(&self) -> bool {
        self.lifecycle == Lifecycle::Ephemeral
    }

    /// Whether this worktree has an active PR (not None, not Merged, not Closed).
    pub fn has_active_pr(&self) -> bool {
        matches!(
            self.pr_status,
            PrStatus::Draft | PrStatus::Open | PrStatus::Approved
        )
    }

    /// Whether this worktree has an associated container.
    pub fn has_container(&self) -> bool {
        self.container.is_some()
    }

    /// Whether this worktree is on a remote host.
    pub fn is_remote(&self) -> bool {
        self.remote_host.is_some()
    }

    /// Get the container ID if available.
    pub fn container_id(&self) -> Option<&str> {
        self.container
            .as_ref()
            .and_then(|c| c.container_id.as_deref())
    }
}
