use std::collections::{HashMap, VecDeque};

pub struct ModalRequest {
    pub id: String,
    pub title: String,
    pub body: String,
    pub confirm_text: String,
    pub cancel_text: String,
    pub(crate) kind: ModalRequestKind,
}

pub(crate) enum ModalRequestKind {
    Confirm,
    TextInput { default_text: String },
}

pub enum ModalResult {
    Confirmed,
    Cancelled,
    TextInput(String),
}

pub(crate) enum ModalKind {
    Confirm,
    TextInput { current_text: String },
}

pub(crate) struct ModalData {
    pub(crate) id: String,
    pub(crate) title: String,
    pub(crate) body: String,
    pub(crate) confirm_text: String,
    pub(crate) cancel_text: String,
    pub(crate) kind: ModalKind,
}

#[derive(Default)]
pub struct Modals {
    pub(crate) active: Option<ModalData>,
    pub(crate) pending_requests: VecDeque<ModalRequest>,
    results: HashMap<String, ModalResult>,
}

impl Modals {
    pub fn show_confirm(
        &mut self,
        id: impl Into<String>,
        title: impl Into<String>,
        body: impl Into<String>,
    ) {
        self.pending_requests.push_back(ModalRequest {
            id: id.into(),
            title: title.into(),
            body: body.into(),
            confirm_text: "Confirm".to_string(),
            cancel_text: "Cancel".to_string(),
            kind: ModalRequestKind::Confirm,
        });
    }

    pub fn show_confirm_with_text(
        &mut self,
        id: impl Into<String>,
        title: impl Into<String>,
        body: impl Into<String>,
        confirm_text: impl Into<String>,
        cancel_text: impl Into<String>,
    ) {
        self.pending_requests.push_back(ModalRequest {
            id: id.into(),
            title: title.into(),
            body: body.into(),
            confirm_text: confirm_text.into(),
            cancel_text: cancel_text.into(),
            kind: ModalRequestKind::Confirm,
        });
    }

    pub fn show_text_input(
        &mut self,
        id: impl Into<String>,
        title: impl Into<String>,
        prompt: impl Into<String>,
        default_text: impl Into<String>,
    ) {
        self.pending_requests.push_back(ModalRequest {
            id: id.into(),
            title: title.into(),
            body: prompt.into(),
            confirm_text: "OK".to_string(),
            cancel_text: "Cancel".to_string(),
            kind: ModalRequestKind::TextInput {
                default_text: default_text.into(),
            },
        });
    }

    pub fn show_text_input_with_text(
        &mut self,
        id: impl Into<String>,
        title: impl Into<String>,
        prompt: impl Into<String>,
        default_text: impl Into<String>,
        confirm_text: impl Into<String>,
        cancel_text: impl Into<String>,
    ) {
        self.pending_requests.push_back(ModalRequest {
            id: id.into(),
            title: title.into(),
            body: prompt.into(),
            confirm_text: confirm_text.into(),
            cancel_text: cancel_text.into(),
            kind: ModalRequestKind::TextInput {
                default_text: default_text.into(),
            },
        });
    }

    pub fn take_result(&mut self, id: &str) -> Option<ModalResult> {
        self.results.remove(id)
    }

    pub fn has_open_modal(&self) -> bool {
        self.active.is_some()
    }

    pub(crate) fn store_result(&mut self, id: String, result: ModalResult) {
        self.results.insert(id, result);
    }

    pub(crate) fn activate_next_pending(&mut self) {
        if self.active.is_none() {
            let Some(request) = self.pending_requests.pop_front() else {
                return;
            };
            let kind = match request.kind {
                ModalRequestKind::Confirm => ModalKind::Confirm,
                ModalRequestKind::TextInput { default_text } => ModalKind::TextInput {
                    current_text: default_text,
                },
            };
            self.active = Some(ModalData {
                id: request.id,
                title: request.title,
                body: request.body,
                confirm_text: request.confirm_text,
                cancel_text: request.cancel_text,
                kind,
            });
        }
    }
}
