// SPDX-License-Identifier: GPL-3.0-or-later

use clap::{Parser, Subcommand, ValueEnum};
use std::io::Write;

/// Brightness controller for external and internal displays via DDC/CI.
#[derive(Parser)]
#[command(name = "temperlux", version, about)]
pub enum Cli {
    /// List all detected displays and their brightness
    List {
        /// Output as JSON (for scripting/waybar/polybar)
        #[arg(long)]
        json: bool,
    },

    /// Get brightness percentage of a display
    Get {
        /// Display number (1-based)
        display: usize,
    },

    /// Set brightness of a display to a percentage
    Set {
        /// Display number (1-based, omit for all displays)
        display: Option<usize>,
        /// Brightness percentage (0-100)
        #[arg(long)]
        percent: f64,
    },

    /// Increase brightness by a percentage
    Increase {
        /// Display number (1-based, omit for all displays)
        display: Option<usize>,
        /// Percentage to increase
        #[arg(long)]
        percent: f64,
    },

    /// Decrease brightness by a percentage
    Decrease {
        /// Display number (1-based, omit for all displays)
        display: Option<usize>,
        /// Percentage to decrease
        #[arg(long)]
        percent: f64,
    },

    /// Rename a display (persisted in config)
    Rename {
        /// Display number (1-based)
        display: usize,
        /// New display name
        name: String,
    },

    /// Set brightness caps for a display (min/max limits)
    Caps {
        /// Display number (1-based)
        display: usize,
        /// Minimum brightness percentage (0-100)
        #[arg(long)]
        min: Option<f64>,
        /// Maximum brightness percentage (0-100)
        #[arg(long)]
        max: Option<f64>,
    },

    /// Set sync mode for multi-display brightness control
    Sync {
        /// Sync mode: off, same, or proportional
        mode: SyncModeArg,
    },

    /// Reorder displays (swap position)
    Order {
        /// Display number to move (1-based)
        display: usize,
        /// Direction to move
        #[arg(long)]
        up: bool,
        /// Direction to move
        #[arg(long)]
        down: bool,
    },

    /// Enable or disable autostart on login
    Autostart {
        /// Enable or disable
        enabled: bool,
    },

    /// Toggle display formatting options
    Config {
        /// Show display numbers in names
        #[arg(long)]
        show_numbers: Option<bool>,

        /// Use 24-hour time format
        #[arg(long)]
        use_24h: Option<bool>,

        /// Show brightness range labels on main window
        #[arg(long)]
        show_range_labels: Option<bool>,
    },

    /// Manage schedule profiles for automatic brightness adjustment
    Schedule {
        #[command(subcommand)]
        command: ScheduleCommand,
    },

    /// Generate shell completions
    Completions {
        /// Shell type
        shell: Shell,
    },
}

#[derive(Subcommand)]
pub enum ScheduleCommand {
    /// List all schedule profiles
    List {
        /// Output as JSON
        #[arg(long)]
        json: bool,
    },

    /// Create a new schedule profile
    Add {
        /// Profile name
        #[arg(long)]
        name: String,

        /// Monitor and brightness pairs as "key=brightness" (e.g., "ddc:1=50,ddc:2=80").
        /// Use "all" as key to set all monitors.
        #[arg(long, value_delimiter = ',')]
        monitors: Vec<String>,

        /// Trigger: absolute time as "HH:MM"
        #[arg(long)]
        time: Option<String>,

        /// Trigger: minutes after sunrise (negative = before)
        #[arg(long, allow_negative_numbers = true)]
        after_sunrise: Option<i32>,

        /// Trigger: minutes after sunset (negative = before)
        #[arg(long, allow_negative_numbers = true)]
        after_sunset: Option<i32>,
    },

    /// Edit an existing schedule profile
    Edit {
        /// Profile ID
        id: String,

        /// New profile name
        #[arg(long)]
        name: Option<String>,

        /// Monitor and brightness pairs as "key=brightness" (e.g., "ddc:1=50,ddc:2=80")
        #[arg(long, value_delimiter = ',')]
        monitors: Option<Vec<String>>,

        /// Trigger: absolute time as "HH:MM"
        #[arg(long)]
        time: Option<String>,

        /// Trigger: minutes after sunrise (negative = before)
        #[arg(long, allow_negative_numbers = true)]
        after_sunrise: Option<i32>,

        /// Trigger: minutes after sunset (negative = before)
        #[arg(long, allow_negative_numbers = true)]
        after_sunset: Option<i32>,

        /// Remove trigger at index (0-based)
        #[arg(long)]
        remove_trigger: Option<usize>,

        /// Enable or disable the schedule
        #[arg(long)]
        enabled: Option<bool>,
    },

    /// Delete a schedule profile
    Delete {
        /// Profile ID
        id: String,
    },

    /// Check schedules and apply any that are due now
    Apply {
        /// Apply a specific profile by ID (skips time check)
        #[arg(long)]
        profile: Option<String>,
    },

    /// Show resolved times for all profiles (for debugging)
    ShowTimes,

    /// Generate systemd user timer units for all enabled profiles
    GenerateTimers,

    /// Set geographic location for sunrise/sunset calculation
    Location {
        /// Latitude (e.g. 41.88 for Chicago)
        #[arg(long, allow_hyphen_values = true)]
        lat: f64,

        /// Longitude (e.g. -87.63 for Chicago)
        #[arg(long, allow_hyphen_values = true)]
        lon: f64,
    },

    /// Auto-detect geographic location from IP address
    DetectLocation,
}

#[derive(Clone, ValueEnum)]
pub enum Shell {
    Bash,
    Zsh,
    Fish,
    Elvish,
}

/// Sync mode argument for CLI.
#[derive(Clone, ValueEnum)]
pub enum SyncModeArg {
    Off,
    Same,
    Proportional,
}

pub fn print_completions(shell: Shell) -> anyhow::Result<()> {
    let mut cmd = <Cli as clap::CommandFactory>::command();
    let name = "temperlux".to_string();
    let mut buf = Vec::new();
    match shell {
        Shell::Bash => clap_complete::generate(clap_complete::Shell::Bash, &mut cmd, &name, &mut buf),
        Shell::Zsh => clap_complete::generate(clap_complete::Shell::Zsh, &mut cmd, &name, &mut buf),
        Shell::Fish => clap_complete::generate(clap_complete::Shell::Fish, &mut cmd, &name, &mut buf),
        Shell::Elvish => clap_complete::generate(clap_complete::Shell::Elvish, &mut cmd, &name, &mut buf),
    }
    std::io::stdout().write_all(&buf)?;
    Ok(())
}
