use std::iter::Enumerate;

use egui::{widgets, TextStyle};
use metadata::{AgeRating, LanguageISO, Metadata};

use eframe::egui;
use parsers::Parsers;
use strum::IntoEnumIterator;

mod metadata;
mod parsers;

const TEXT_SIZE_SMALL: f32 = 1.0;
const TEXT_SIZE_MEDIUM: f32 = 1.2;
const TEXT_SIZE_LARGE: f32 = 1.4;

fn main() -> Result<(), eframe::Error> {
    env_logger::init();
    let options = eframe::NativeOptions {
        initial_window_size: Some(egui::vec2(1280.0, 720.0)),
        ..Default::default()
    };
    eframe::run_native(
        "Metadata Generator",
        options,
        Box::new(|cc| {
            cc.egui_ctx.set_pixels_per_point(TEXT_SIZE_MEDIUM);
            Box::<Generator>::default()
        }),
    )
}

struct Generator<'a> {
    show_all: bool,
    metadata: Vec<Metadata<'a>>,
    selected_parser: Parsers,
    use_file: bool,
    meta_path: Option<String>,
    bundle: bool,
    bundle_source: Option<String>,
    bundle_path: Option<String>,
    footer_height: f32,
}

impl Default for Generator<'_> {
    fn default() -> Self {
        Self {
            show_all: false,
            metadata: vec![Metadata::default()],
            selected_parser: Parsers::JNovel,
            use_file: true,
            meta_path: None,
            bundle: false,
            bundle_source: None,
            bundle_path: None,
            footer_height: 0.0,
        }
    }
}

impl eframe::App for Generator<'_> {
    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
        // Non-Metadata Options
        egui::SidePanel::right("Options")
            .resizable(false)
            .min_width(ctx.screen_rect().width() / 3.0)
            .max_width(ctx.screen_rect().width() / 3.0)
            .show(ctx, |panel| {
                panel.heading("Options");
                panel.horizontal(|row| {
                    row.label("Parser: ");
                    egui::containers::ComboBox::from_label("")
                        .selected_text(self.selected_parser.to_string())
                        .show_ui(row, |ui| {
                            for rating in Parsers::iter() {
                                let text = rating.to_string().clone();
                                if ui
                                    .selectable_value(&mut self.selected_parser, rating, text)
                                    .clicked()
                                {
                                    match self.selected_parser {
                                        Parsers::Fakku | Parsers::Irodori => {
                                            self.use_file = false; // TODO change to use Parser default
                                        }
                                        Parsers::JNovel => {
                                            self.use_file = true; // TODO change to use Parser default
                                        }
                                    }
                                };
                            }
                        });
                });

                panel.horizontal(|row| {
                    row.label("Parser Source: ");
                    if row
                        .add(widgets::SelectableLabel::new(self.use_file, "File"))
                        .clicked()
                    {
                        self.use_file = true;
                    }

                    if row
                        .add(widgets::SelectableLabel::new(!self.use_file, "URL"))
                        .clicked()
                    {
                        self.use_file = false;
                    }
                });

                let file_label;
                if self.use_file {
                    file_label = "File Path";
                } else {
                    file_label = "URL";
                }
                text_input_option(panel, &mut self.meta_path, file_label, self.use_file);

                // TODO this feels wrong, there must be a better way
                panel.add_space(self.footer_height * 0.1);
                panel.separator();
                panel.add_space(self.footer_height * 0.1);

                panel.horizontal(|row| {
                    row.label("Perform Bundle: ");
                    row.add(widgets::Checkbox::new(&mut self.bundle, ""));
                });

                if self.bundle {
                    text_input_option(panel, &mut self.bundle_source, "Images Folder", true);
                    text_input_option(panel, &mut self.bundle_path, "Output Path", true);
                }

                panel.add_space(self.footer_height * 2.0);

                panel.horizontal(|elem| {
                    elem.vertical_centered(|centered| {
                        if centered.button("Generate Metadata").clicked() {
                            // Run Metadata Generation
                            // DO NOT SAVE RESULTS YET ONLY POPULATE DATA
                            println!("Ran Generation (not yet)");
                        }
                    })
                });

                panel.add_space(panel.available_height() - self.footer_height);

                self.footer_height = panel
                    .horizontal(|row| {
                        let ppp = ctx.pixels_per_point();
                        row.label("Text Size:");
                        if row
                            .add(widgets::RadioButton::new(ppp == TEXT_SIZE_SMALL, "Small"))
                            .clicked()
                        {
                            ctx.set_pixels_per_point(TEXT_SIZE_SMALL);
                        }

                        if row
                            .add(widgets::RadioButton::new(ppp == TEXT_SIZE_MEDIUM, "Medium"))
                            .clicked()
                        {
                            ctx.set_pixels_per_point(TEXT_SIZE_MEDIUM);
                        }

                        if row
                            .add(widgets::RadioButton::new(ppp == TEXT_SIZE_LARGE, "Large"))
                            .clicked()
                        {
                            ctx.set_pixels_per_point(TEXT_SIZE_LARGE);
                        }
                    })
                    .response
                    .rect
                    .height();
            });

        // Metadata Options
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("Metadata");

            // Title & Series
            text_input(ui, &mut self.metadata[0].series, "Series", false);
            text_input(ui, &mut self.metadata[0].title, "Title", false);

            // Volume and Chapter Info
            ui.horizontal(|row| {
                row.label("Volume:");
                if row.button("-").clicked() {
                    self.metadata[0].volume -= 1;
                }
                row.label(format!("{}", self.metadata[0].volume));
                if row.button("+").clicked() {
                    self.metadata[0].volume += 1;
                }

                row.label("Chapter:");
                if row.button("-").clicked() {
                    self.metadata[0].number -= 1;
                }
                row.label(format!("{}", self.metadata[0].number));
                if row.button("+").clicked() {
                    self.metadata[0].number += 1;
                }
            });

            ui.horizontal(|row| {
                row.label("Series Chapter Count:");
                if row.button("-").clicked() {
                    self.metadata[0].count -= 1;
                }
                row.label(format!("{}", self.metadata[0].count));
                if row.button("+").clicked() {
                    self.metadata[0].count += 1;
                }
            });

            // TODO Multiline Summary
            ui.label("TODO: Summary Edit");
            if let Some(summary) = &self.metadata[0].summary {
                ui.label(summary);
            }

            // Date Inputs
            let glyph_width = ctx
                .fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });

            let mut year_text = self.metadata[0].year.to_string();

            ui.horizontal(|row| {
                row.label("Release Date:");
                if row
                    .add(
                        widgets::text_edit::TextEdit::singleline(&mut year_text)
                            .desired_width(5.0 * glyph_width),
                    )
                    .changed()
                {
                    let trimmed = year_text.trim();
                    if trimmed == "0" {
                        self.metadata[0].year = -1;
                        self.metadata[0].month = -1;
                        self.metadata[0].day = -1;
                    } else {
                        self.metadata[0].year =
                            trimmed.parse::<i16>().unwrap_or(self.metadata[0].year);
                    }
                };

                if self.metadata[0].year >= 1970 {
                    let mut month_text = self.metadata[0].month.to_string();
                    if row
                        .add(
                            widgets::text_edit::TextEdit::singleline(&mut month_text)
                                .desired_width(3.0 * glyph_width),
                        )
                        .changed()
                    {
                        let trimmed = month_text.trim();
                        if trimmed == "0" {
                            self.metadata[0].month = -1;
                            self.metadata[0].day = -1;
                        } else {
                            self.metadata[0].month = month_text
                                .trim()
                                .parse::<i8>()
                                .unwrap_or(self.metadata[0].month);
                        }
                    };

                    if self.metadata[0].month >= 0 {
                        let mut day_text = self.metadata[0].day.to_string();
                        if row
                            .add(
                                widgets::text_edit::TextEdit::singleline(&mut day_text)
                                    .desired_width(3.0 * glyph_width),
                            )
                            .changed()
                        {
                            let trimmed = day_text.trim();
                            if trimmed == "0" {
                                self.metadata[0].day = -1;
                            } else {
                                self.metadata[0].day = day_text
                                    .trim()
                                    .parse::<i8>()
                                    .unwrap_or(self.metadata[0].day);
                            }
                        };
                    }
                }
            });

            // People involved
            text_input_option(ui, &mut self.metadata[0].writer, "Author", false);
            text_input_option(ui, &mut self.metadata[0].letterer, "Typesetter", false);
            text_input_option(ui, &mut self.metadata[0].editor, "Editor", false);
            text_input_option(ui, &mut self.metadata[0].translator, "Translator", false);
            text_input_option(ui, &mut self.metadata[0].publisher, "Publisher", false);

            /*
            tags: Vec<String>,
            characters: Vec<String>,
            */
            text_input(ui, &mut self.metadata[0].genre, "Genre", false);
            // TODO tag list (List of bordered labels with plus that opens a new text edit)
            ui.horizontal(|row| {
                row.label("Page Count:");
                if row.button("-").clicked() {
                    self.metadata[0].page_count -= 1;
                }
                row.label(format!("{}", self.metadata[0].page_count));
                if row.button("+").clicked() {
                    self.metadata[0].page_count += 1;
                }
            });
            //text_input(ui, &mut self.metadata[0].page_count, "Page Count", false);

            // Lang Drop Down
            ui.horizontal(|row| {
                row.label("Language: ");
                egui::containers::ComboBox::from_label("a")
                    .selected_text(self.metadata[0].language.to_string())
                    .show_ui(row, |ui| {
                        for language in LanguageISO::iter() {
                            let text = language.to_string().clone();
                            ui.selectable_value(&mut self.metadata[0].language, language, text);
                        }
                    });
            });

            // TODO same as with Tags but for characters

            // Age Rating Drop Down
            ui.horizontal(|row| {
                row.label("Age Rating: ");
                egui::containers::ComboBox::from_label("b")
                    .selected_text(self.metadata[0].age_rating.to_string())
                    .show_ui(row, |ui| {
                        for rating in AgeRating::iter() {
                            let text = rating.to_string().clone();
                            ui.selectable_value(&mut self.metadata[0].age_rating, rating, text);
                        }
                    });
            });

            ui.horizontal(|elem| {
                elem.vertical_centered(|centered| {
                    if centered.button("Save Metadata").clicked() {
                        // Run Metadata Generation
                        // DO NOT SAVE RESULTS YET ONLY POPULATE DATA
                        self.metadata[0].save_to_xml("/home/neshura/Repositories/manga-hentai-metadata-generator/ComicInfo.xml")
                    }
                })
            });

            if self.show_all {
                ui.label(format!("Not Implemented yet."));
            }
        });
    }
}

pub(crate) fn text_input_option(
    ui: &mut egui::Ui,
    option: &mut Option<String>,
    label: &str,
    file_picker: bool,
) -> egui::InnerResponse<()> {
    let zero_width =
        2.0 * ui.fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });

    ui.horizontal(|row| {
        row.label(format!("{}:", label));
        if let Some(ref mut text) = option {
            let dynamic_width = zero_width
                + text
                    .chars()
                    .map(|c| {
                        row.fonts(|f| -> f32 {
                            f.glyph_width(&TextStyle::Body.resolve(row.style()), c)
                        })
                    })
                    .sum::<f32>();

            row.add(
                widgets::text_edit::TextEdit::singleline(text).desired_width(
                    if dynamic_width >= zero_width * 3.0 {
                        dynamic_width
                    } else {
                        zero_width * 3.0
                    },
                ),
            );
            if text == "" {
                *option = None;
            }
        } else {
            let mut init = "".to_string();
            row.add(
                widgets::text_edit::TextEdit::singleline(&mut init).desired_width(zero_width * 3.0),
            );
            if init != "" {
                *option = Some(init);
            }
        }

        if file_picker {
            if row.button("...").clicked() {
                if let Some(path) = rfd::FileDialog::new().pick_file() {
                    *option = Some(path.display().to_string());
                }
            }
        }
    })
}

pub(crate) fn text_input(
    ui: &mut egui::Ui,
    option: &mut String,
    label: &str,
    file_picker: bool,
) -> egui::InnerResponse<()> {
    let zero_width =
        2.0 * ui.fonts(|f| -> f32 { f.glyph_width(&TextStyle::Body.resolve(ui.style()), '0') });

    ui.horizontal(|row| {
        row.label(format!("{}:", label));
        let dynamic_width = zero_width
            + option
                .chars()
                .map(|c| {
                    row.fonts(|f| -> f32 {
                        f.glyph_width(&TextStyle::Body.resolve(row.style()), c)
                    })
                })
                .sum::<f32>();

        row.add(
            widgets::text_edit::TextEdit::singleline(option).desired_width(
                if dynamic_width >= zero_width * 3.0 {
                    dynamic_width
                } else {
                    zero_width * 3.0
                },
            ),
        );

        if file_picker {
            if row.button("...").clicked() {
                if let Some(path) = rfd::FileDialog::new().pick_file() {
                    *option = path.display().to_string();
                }
            }
        }
    })
}