#![allow(clippy::unwrap_used)]
use std::collections::HashMap;
use ironcalc_base::expressions::parser::{new_parser_english, stringify::to_excel_string};
use ironcalc_base::expressions::types::CellReferenceRC;
use ironcalc_base::types::{SheetState, Workbook};
use super::escape::escape_xml;
use super::xml_constants::XML_DECLARATION;
pub(crate) fn get_workbook_xml(workbook: &Workbook, selected_sheet: u32) -> String {
let mut sheets_str: Vec<String> = vec![];
let mut sheet_id_to_sheet_index: HashMap<u32, u32> = HashMap::new();
for (sheet_index, worksheet) in workbook.worksheets.iter().enumerate() {
let name = &worksheet.name;
let name = escape_xml(name);
let sheet_id = worksheet.sheet_id;
let state_str = match &worksheet.state {
SheetState::Visible => "",
SheetState::Hidden => " state=\"hidden\"",
SheetState::VeryHidden => " state=\"veryHidden\"",
};
sheets_str.push(format!(
"<sheet name=\"{name}\" sheetId=\"{sheet_id}\" r:id=\"rId{}\"{state_str}/>",
sheet_index + 1
));
sheet_id_to_sheet_index.insert(sheet_id, sheet_index as u32);
}
let worksheet_names: Vec<String> = workbook.worksheets.iter().map(|s| s.name.clone()).collect();
let mut parser = new_parser_english(
worksheet_names,
workbook.get_defined_names_with_scope(),
workbook.tables.clone(),
);
let parse_context = CellReferenceRC {
sheet: workbook
.worksheets
.first()
.map(|ws| ws.name.clone())
.unwrap_or_else(|| "Sheet1".to_string()),
row: 1,
column: 1,
};
let mut defined_names_str: Vec<String> = vec![];
for defined_name in &workbook.defined_names {
let name = &defined_name.name;
let name = escape_xml(name);
let local_sheet_id = if let Some(sheet_id) = defined_name.sheet_id {
let excel_local_sheet_id = sheet_id_to_sheet_index.get(&sheet_id).unwrap();
format!(" localSheetId=\"{excel_local_sheet_id}\"")
} else {
"".to_string()
};
let formula_body = defined_name
.formula
.strip_prefix('=')
.unwrap_or(&defined_name.formula);
let node = parser.parse(formula_body, &parse_context);
let formula = to_excel_string(&node, &parse_context);
let formula = escape_xml(&formula);
defined_names_str.push(format!(
"<definedName name=\"{name}\"{local_sheet_id}>{formula}</definedName>"
))
}
let sheets = sheets_str.join("");
let defined_names = defined_names_str.join("");
format!("{XML_DECLARATION}\n\
<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\
<bookViews>
<workbookView activeTab=\"{selected_sheet}\"/>\
</bookViews>
<sheets>\
{sheets}\
</sheets>\
<definedNames>\
{defined_names}\
</definedNames>\
<calcPr/>\
</workbook>")
}