// crates/atomcode-tuix/src/modals/mod.rs
//
// Modal overlay abstraction. Each of the three existing overlays
// (`/model` picker, `/provider` wizard, `/resume` session picker)
// implements `Modal`, and the event loop owns exactly one
// `active_modal: Option<Box<dyn Modal>>`. Adding a fourth modal means
// "new struct + new impl" — not another `Option<T>` field and another
// `handle_X_key` fn and another branch in `handle_input`.
//
// Modal impl lives next to the struct definition (for now still in
// `event_loop.rs`; Step 5 will move each modal to its own file under
// `crates/atomcode-tuix/src/modals/`). This module only defines the
// trait + action enum.

use anyhow::Result;
use crossterm::event::{KeyCode, KeyModifiers};

use crate::event_loop::{Buffer, LoopCtx};
use crate::render::Renderer;
use crate::state::UiState;

pub mod dir_picker;
pub mod issue_wizard;
pub mod language_picker;
pub mod model_picker;
pub mod onboarding_wizard;
pub mod plugin_manager;
mod qr;
pub mod provider_wizard;
pub mod session_picker;
pub use dir_picker::DirPicker;
pub use issue_wizard::IssueWizard;
pub use language_picker::LanguagePicker;
pub use model_picker::ModelPicker;
pub use onboarding_wizard::OnboardingWizard;
pub use plugin_manager::PluginManager;
pub use provider_wizard::ProviderWizard;
pub use session_picker::SessionPicker;

/// Result of a modal consuming one key event.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModalAction {
    /// Modal stays active; keep dispatching keys to it next time.
    Continue,
    /// Modal finished (user hit Esc, or the submit side-effect is
    /// done). Caller must drop `active_modal` and redraw idle.
    Close,
}

/// A modal overlay: takes over key handling until it returns
/// `ModalAction::Close`. The implementation owns its own state (the
/// selected index, the wizard step, the filter query, etc.) and is
/// responsible for painting itself whenever its visible state changes
/// — the event loop only calls `draw` once at open time and once more
/// after `Close` to restore the idle prompt.
pub trait Modal: Send {
    /// Process one keystroke. Must either fully handle it (including
    /// any re-paint the modal wants) or report that the modal is now
    /// done so the caller can tear it down.
    fn handle_key(
        &mut self,
        code: KeyCode,
        mods: KeyModifiers,
        buf: &mut Buffer,
        state: &mut UiState,
        ctx: &mut LoopCtx,
        renderer: &mut dyn Renderer,
    ) -> Result<ModalAction>;

    /// Paint the modal against the current terminal state. Called once
    /// when the modal is installed into `active_modal`; `handle_key`
    /// is expected to handle subsequent repaints after each key.
    fn draw(&self, buf: &Buffer, state: &UiState, ctx: &LoopCtx, renderer: &mut dyn Renderer);

    /// Handle a bracketed-paste payload while the modal is active.
    /// Default: append the text to `buf` (so text-input wizard steps
    /// naturally accept URL / API-key paste) and redraw. Modals that
    /// only present pickers (no text input) can leave the default —
    /// buf updates are harmless when the modal isn't displaying it.
    fn handle_paste(
        &mut self,
        text: &str,
        buf: &mut Buffer,
        state: &mut UiState,
        ctx: &mut LoopCtx,
        renderer: &mut dyn Renderer,
    ) -> Result<ModalAction> {
        buf.insert_paste(text.to_string());
        self.draw(buf, state, ctx, renderer);
        Ok(ModalAction::Continue)
    }

    /// Notify the modal that an async plugin job finished, so it can refresh
    /// any cached lists it is displaying. Default: ignore. Only the
    /// interactive `/plugin` manager overrides this. The event loop calls it
    /// before rendering the job result and before redrawing the modal.
    fn on_plugin_event(&mut self, _ev: &atomcode_core::plugin::PluginJobEvent) {}
}