use leptos_tiptap::TiptapEditorHandle;
use serde_json::Value;

#[derive(Clone, Copy)]
pub(crate) enum TableToolbarAction {
    AddRowAfter,
    AddColumnAfter,
    DeleteRow,
    DeleteColumn,
    ClearCell,
    DeleteTable,
}

#[derive(Clone, Copy)]
pub(crate) enum TableOptionAction {
    ToggleHeaderRow,
    ToggleHeaderColumn,
    ToggleHiddenBorders,
}

impl TableToolbarAction {
    pub(crate) fn id(self) -> &'static str {
        match self {
            Self::AddRowAfter => "add-row-after",
            Self::AddColumnAfter => "add-column-after",
            Self::DeleteRow => "delete-row",
            Self::DeleteColumn => "delete-column",
            Self::ClearCell => "clear-cell",
            Self::DeleteTable => "delete-table",
        }
    }

    pub(crate) fn icon(self) -> &'static str {
        match self {
            Self::AddRowAfter => "+R",
            Self::AddColumnAfter => "+C",
            Self::DeleteRow => "-R",
            Self::DeleteColumn => "-C",
            Self::ClearCell => "⌫",
            Self::DeleteTable => "×",
        }
    }

    pub(crate) fn title(self) -> &'static str {
        match self {
            Self::AddRowAfter => "下方插入行",
            Self::AddColumnAfter => "右侧插入列",
            Self::DeleteRow => "删除当前行",
            Self::DeleteColumn => "删除当前列",
            Self::ClearCell => "清空当前单元格",
            Self::DeleteTable => "删除表格",
        }
    }
}

pub(crate) const TABLE_TOOLBAR_ACTIONS: [TableToolbarAction; 6] = [
    TableToolbarAction::AddRowAfter,
    TableToolbarAction::AddColumnAfter,
    TableToolbarAction::ClearCell,
    TableToolbarAction::DeleteRow,
    TableToolbarAction::DeleteColumn,
    TableToolbarAction::DeleteTable,
];

impl TableOptionAction {
    pub(crate) fn id(self) -> &'static str {
        match self {
            Self::ToggleHeaderRow => "toggle-header-row",
            Self::ToggleHeaderColumn => "toggle-header-column",
            Self::ToggleHiddenBorders => "toggle-hidden-borders",
        }
    }

    pub(crate) fn title(self) -> &'static str {
        match self {
            Self::ToggleHeaderRow => "标题行",
            Self::ToggleHeaderColumn => "标题列",
            Self::ToggleHiddenBorders => "隐藏边框线",
        }
    }
}

pub(crate) const TABLE_OPTION_ACTIONS: [TableOptionAction; 3] = [
    TableOptionAction::ToggleHeaderRow,
    TableOptionAction::ToggleHeaderColumn,
    TableOptionAction::ToggleHiddenBorders,
];

pub(crate) fn run_table_toolbar_action(
    editor: TiptapEditorHandle,
    action: TableToolbarAction,
) -> Result<&'static str, String> {
    let result = match action {
        TableToolbarAction::AddRowAfter => editor.add_table_row_after(),
        TableToolbarAction::AddColumnAfter => editor.add_table_column_after(),
        TableToolbarAction::DeleteRow => editor.delete_table_row(),
        TableToolbarAction::DeleteColumn => editor.delete_table_column(),
        TableToolbarAction::ClearCell => editor.clear_table_cell(),
        TableToolbarAction::DeleteTable => editor.delete_table(),
    };
    result
        .map(|_| action.title())
        .map_err(|err| format!("命令执行失败：{err}"))
}

pub(crate) fn run_table_option_action(
    editor: TiptapEditorHandle,
    action: TableOptionAction,
) -> Result<&'static str, String> {
    let result = match action {
        TableOptionAction::ToggleHeaderRow => editor.toggle_table_header_row(),
        TableOptionAction::ToggleHeaderColumn => editor.toggle_table_header_column(),
        TableOptionAction::ToggleHiddenBorders => editor.toggle_table_hidden_borders(),
    };
    result
        .map(|_| action.title())
        .map_err(|err| format!("命令执行失败：{err}"))
}

fn first_table_node(value: &Value) -> Option<&Value> {
    if value.get("type").and_then(Value::as_str) == Some("table") {
        return Some(value);
    }
    if let Some(table) = value
        .get("props")
        .and_then(|props| props.get("tiptapTable"))
        .and_then(first_table_node)
    {
        return Some(table);
    }
    for key in ["content", "children"] {
        if let Some(children) = value.get(key).and_then(Value::as_array) {
            if let Some(table) = children.iter().find_map(first_table_node) {
                return Some(table);
            }
        }
    }
    None
}

pub(crate) fn table_option_checked(document: &Value, action: TableOptionAction) -> bool {
    let Some(table) = first_table_node(document) else {
        return false;
    };
    match action {
        TableOptionAction::ToggleHiddenBorders => table
            .get("attrs")
            .and_then(|attrs| attrs.get("hiddenBorders"))
            .and_then(Value::as_bool)
            .unwrap_or(false),
        TableOptionAction::ToggleHeaderRow => table
            .get("content")
            .and_then(Value::as_array)
            .and_then(|rows| rows.first())
            .and_then(|row| row.get("content"))
            .and_then(Value::as_array)
            .map(|cells| {
                !cells.is_empty()
                    && cells
                        .iter()
                        .all(|cell| cell.get("type").and_then(Value::as_str) == Some("tableHeader"))
            })
            .unwrap_or(false),
        TableOptionAction::ToggleHeaderColumn => table
            .get("content")
            .and_then(Value::as_array)
            .map(|rows| {
                !rows.is_empty()
                    && rows.iter().all(|row| {
                        row.get("content")
                            .and_then(Value::as_array)
                            .and_then(|cells| cells.first())
                            .and_then(|cell| cell.get("type"))
                            .and_then(Value::as_str)
                            == Some("tableHeader")
                    })
            })
            .unwrap_or(false),
    }
}
