/*
    Hurry Curry! - a game about cooking
    Copyright (C) 2026 Hurry Curry! Contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

*/

use crate::{export_load, load_ini};
use anyhow::{Context, Result, anyhow};
use std::{
    collections::BTreeMap,
    fmt::Write as W2,
    fs::{File, read_to_string},
    io::Write,
    path::{Path, PathBuf},
};

pub fn export_po(inputs: &[PathBuf], output: &Path, id_map: Option<PathBuf>) -> Result<()> {
    let ini = export_load(&inputs)?;
    let id_map = id_map.map(|path| load_ini(&path)).transpose()?;
    File::create(output)?.write_all(
        format!(
            r#"
msgid ""
msgstr ""
"Language: {}\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

{}"#,
            inputs
                .first()
                .ok_or(anyhow!("at least one input required"))?
                .file_stem()
                .ok_or(anyhow!("file name empty"))?
                .to_string_lossy(),
            ini.into_iter()
                .try_fold(String::new(), |mut a, (mut key, value)| {
                    if let Some(id_map) = &id_map
                        && let Some(new_id) = id_map.get(&key)
                    {
                        key = new_id.to_owned()
                    }
                    let key = serde_json::to_string(&key)?;
                    let value = serde_json::to_string(&value)?;
                    writeln!(a, "msgid {key}\nmsgstr {value}\n\n",)?;
                    Ok::<_, anyhow::Error>(a)
                })?
        )
        .as_bytes(),
    )?;
    Ok(())
}

pub fn import_old_po(reference: &Path, input: &Path, output: &Path) -> Result<()> {
    let reference = read_to_string(reference)?;
    let input = read_to_string(input)?;

    let id_reverse = reference
        .lines()
        .skip(1)
        .map(|l| {
            l.split_once("=")
                .map(|(k, v)| (v, k))
                .ok_or(anyhow!("invalid ini"))
        })
        .collect::<Result<BTreeMap<&str, &str>>>()?;

    let mut outmap = BTreeMap::new();
    let mut mode = 0;
    let mut msgid = String::new();
    let mut msgstr = String::new();
    for (i, mut line) in input.lines().enumerate() {
        if line.starts_with("#") {
            continue;
        }
        if line.is_empty() {
            continue;
        }
        if let Some(rest) = line.strip_prefix("msgid ") {
            if !msgid.is_empty() {
                if let Some(id) = id_reverse.get(&msgid.as_str()) {
                    outmap.insert(id.to_owned(), msgstr.clone());
                } else {
                    eprintln!("warning: message id {msgid:?} is unknown")
                }
            }
            line = rest;
            msgid = String::new();
            mode = 1;
        } else if let Some(rest) = line.strip_prefix("msgstr ") {
            line = rest;
            msgstr = String::new();
            mode = 2;
        } else if line.starts_with("msgctxt ") {
            mode = 0;
            eprintln!("warning: msgctxt not implemented (line {})", i + 1);
            continue;
        }
        let frag = serde_json::from_str::<String>(line).context(anyhow!("line {}", i + 1))?;
        match mode {
            0 => (),
            1 => msgid.push_str(&frag),
            2 => msgstr.push_str(&frag),
            _ => unreachable!(),
        };
    }

    File::create(output)?.write_all(
        outmap
            .into_iter()
            .try_fold("[hurrycurry]\n".to_string(), |mut a, (k, v)| {
                writeln!(a, "{k}={v}")?;
                Ok::<_, anyhow::Error>(a)
            })?
            .as_bytes(),
    )?;

    Ok(())
}

pub fn import_old_pot(input: &Path, output: &Path) -> Result<()> {
    let output_raw = read_to_string(&output).unwrap_or("".to_owned());
    let input = read_to_string(input)?;

    let mut output_flip = output_raw
        .lines()
        .skip(1)
        .map(|l| {
            l.split_once("=")
                .map(|(k, v)| (v.to_owned(), k.to_owned()))
                .ok_or(anyhow!("invalid ini"))
        })
        .collect::<Result<BTreeMap<String, String>>>()?;

    let mut id = false;
    let mut msgid = String::new();
    for (i, mut line) in input.lines().enumerate() {
        if line.starts_with("#") {
            continue;
        }
        if line.is_empty() {
            continue;
        }
        if let Some(rest) = line.strip_prefix("msgid ") {
            if !msgid.is_empty() && !output_flip.contains_key(&msgid) {
                output_flip.insert(msgid.replace("\n", "\\n"), format!("unknown{i}"));
            }
            line = rest;
            id = true;
            msgid = String::new();
        } else if line.starts_with("msgctxt ") || line.starts_with("msgstr ") {
            id = false;
            continue;
        }
        if id {
            let frag = serde_json::from_str::<String>(line).context(anyhow!("line {}", i + 1))?;
            msgid.push_str(frag.as_str());
        }
    }

    let output_unflip = output_flip
        .into_iter()
        .map(|(v, k)| (k, v))
        .collect::<BTreeMap<_, _>>();

    File::create(output)?.write_all(
        output_unflip
            .into_iter()
            .try_fold("[hurrycurry]\n".to_string(), |mut a, (k, v)| {
                writeln!(a, "{k}={v}")?;
                Ok::<_, anyhow::Error>(a)
            })?
            .as_bytes(),
    )?;

    Ok(())
}
