/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::cli::Action;
use dialoguer::{Confirm, FuzzySelect, Input, theme::ColorfulTheme};
use jellycache::init_cache_dummy;
use jellyimport::plugins::trakt::{Trakt, TraktKind};
use log::warn;
use std::{
    env::var,
    fmt::Display,
    fs::{OpenOptions, rename},
    io::Write,
    path::{Path, PathBuf},
};
use tokio::runtime::Handle;

pub fn add(action: Action, rt: &Handle) -> anyhow::Result<()> {
    init_cache_dummy()?;
    match action {
        Action::Add { media } => {
            let theme = ColorfulTheme::default();

            let search_kinds = if media.is_dir() {
                &[TraktKind::Show, TraktKind::Season]
            } else {
                &[TraktKind::Movie, TraktKind::Episode]
            };

            let (trakt_object, trakt_kind) = loop {
                let name: String = Input::with_theme(&theme)
                    .with_prompt("Search by title")
                    .default(path_to_query(&media))
                    .interact_text()
                    .unwrap();

                let trakt = Trakt::new(&var("TRAKT_API_KEY").unwrap());
                let results = trakt.search(search_kinds, &name, rt)?;

                if results.is_empty() {
                    warn!("no search results");
                    continue;
                }

                let correct = FuzzySelect::with_theme(&theme)
                    .items(&*results)
                    .default(0)
                    .with_prompt("Metadata Source")
                    .interact_opt()
                    .unwrap();

                if let Some(o) = correct {
                    break (results[o].inner.inner().to_owned(), results[o].r#type);
                }
            };

            if media.is_dir() {
                let flagspath = media.join("flags");
                let flag = format!(
                    "trakt={}:{}\n",
                    match trakt_kind {
                        TraktKind::Movie => "movie",
                        TraktKind::Show => "show",
                        TraktKind::Season => "season",
                        TraktKind::Episode => "episode",
                        _ => unreachable!(),
                    },
                    trakt_object.ids.trakt.unwrap()
                );

                if Confirm::with_theme(&theme)
                    .with_prompt(format!("Append {flag:?} to {flagspath:?}?"))
                    .default(true)
                    .interact()
                    .unwrap()
                {
                    OpenOptions::new()
                        .append(true)
                        .write(true)
                        .create(true)
                        .open(flagspath)?
                        .write_all(flag.as_bytes())?;
                }
            } else {
                let ext = media
                    .extension()
                    .map(|e| format!(".{}", e.to_string_lossy()))
                    .unwrap_or("mkv".to_string());

                let stem = media.file_name().unwrap().to_string_lossy().to_string();
                let stem = stem.split_once(".").unwrap_or((stem.as_str(), "")).0;
                let mut newpath = media.parent().unwrap().join(format!(
                    "{stem}.trakt-{}{ext}",
                    trakt_object.ids.trakt.unwrap()
                ));
                let mut n = 1;
                while newpath.exists() {
                    newpath = media
                        .parent()
                        .unwrap()
                        .join(format!("{stem}.alt-{n}{ext}",));
                    n += 1;
                }

                if Confirm::with_theme(&theme)
                    .with_prompt(format!("Rename {media:?} -> {newpath:?}?"))
                    .default(true)
                    .interact()
                    .unwrap()
                {
                    rename(media, newpath)?;
                }
            }

            Ok(())
        }
        _ => unreachable!(),
    }
}

// fn validate_id(s: &String) -> anyhow::Result<()> {
//     if &make_id(s) == s {
//         Ok(())
//     } else {
//         bail!("invalid id")
//     }
// }
// fn make_id(s: &str) -> String {
//     let mut out = String::new();
//     for s in s.chars() {
//         match s {
//             'a'..='z' | '0'..='9' => out.push(s),
//             'A'..='Z' => out.push(s.to_ascii_lowercase()),
//             '-' | ' ' | '_' | ':' => out.push('-'),
//             _ => (),
//         }
//     }
//     out
// }

fn path_to_query(path: &Path) -> String {
    let stem = path.file_name().unwrap().to_string_lossy().to_string();
    let stem = stem.split_once(".").unwrap_or((stem.as_str(), "")).0;
    stem.replace("-", " ")
}

pub struct PathDisplay(PathBuf);
impl Display for PathDisplay {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("/")?;
        f.write_str(self.0.to_str().unwrap())
    }
}
