// Copyright (C) 2024 Melody Madeline Lyons
//
// This file is part of Luminol.
//
// Luminol is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Luminol 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Luminol.  If not, see <http://www.gnu.org/licenses/>.
//
//     Additional permission under GNU GPL version 3 section 7
//
// If you modify this Program, or any covered work, by linking or combining
// it with Steamworks API by Valve Corporation, containing parts covered by
// terms of the Steamworks API by Valve Corporation, the licensors of this
// Program grant you additional permission to convey the resulting work.

use crate::components::{EnumComboBox, Field, IdVecSelection, OptionalIdComboBox, UiExt};

#[derive(Default)]
pub struct Window {
    selected_armor_name: Option<String>,
    previous_armor: Option<usize>,

    view: crate::components::DatabaseView,
}

impl Window {
    pub fn new() -> Self {
        Default::default()
    }
}

impl luminol_core::Window for Window {
    fn id(&self) -> egui::Id {
        egui::Id::new("armor_editor")
    }

    fn requires_filesystem(&self) -> bool {
        true
    }

    fn show(
        &mut self,
        ctx: &egui::Context,
        open: &mut bool,
        update_state: &mut luminol_core::UpdateState<'_>,
    ) {
        let data = std::mem::take(update_state.data); // take data to avoid borrow checker issues
        let mut armors = data.armors();
        let system = data.system();
        let states = data.states();

        let mut modified = false;

        self.selected_armor_name = None;

        let name = if let Some(name) = &self.selected_armor_name {
            format!("Editing armor {:?}", name)
        } else {
            "Armor Editor".into()
        };

        let response = egui::Window::new(name)
            .id(self.id())
            .default_width(500.)
            .open(open)
            .show(ctx, |ui| {
                self.view.show(
                    ui,
                    update_state,
                    "Armor",
                    &mut armors.data,
                    |armor| format!("{:0>4}: {}", armor.id + 1, armor.name),
                    |ui, armors, id, update_state| {
                        let armor = &mut armors[id];
                        self.selected_armor_name = Some(armor.name.clone());

                        ui.with_padded_stripe(false, |ui| {
                            modified |= ui
                                .add(Field::new(
                                    "Name",
                                    egui::TextEdit::singleline(&mut armor.name)
                                        .desired_width(f32::INFINITY),
                                ))
                                .changed();

                            modified |= ui
                                .add(Field::new(
                                    "Description",
                                    egui::TextEdit::multiline(&mut armor.description)
                                        .desired_width(f32::INFINITY),
                                ))
                                .changed();
                        });

                        ui.with_padded_stripe(true, |ui| {
                            ui.columns(2, |columns| {
                                modified |= columns[0]
                                    .add(Field::new(
                                        "Kind",
                                        EnumComboBox::new((armor.id, "kind"), &mut armor.kind),
                                    ))
                                    .changed();

                                modified |= columns[1]
                                    .add(Field::new(
                                        "Auto State",
                                        OptionalIdComboBox::new(
                                            update_state,
                                            (armor.id, "auto_state"),
                                            &mut armor.auto_state_id,
                                            0..states.data.len(),
                                            |id| {
                                                states.data.get(id).map_or_else(
                                                    || "".into(),
                                                    |s| format!("{:0>4}: {}", id + 1, s.name),
                                                )
                                            },
                                        ),
                                    ))
                                    .changed();
                            });
                        });

                        ui.with_padded_stripe(false, |ui| {
                            ui.columns(4, |columns| {
                                modified |= columns[0]
                                    .add(Field::new(
                                        "Price",
                                        egui::DragValue::new(&mut armor.price).range(0..=i32::MAX),
                                    ))
                                    .changed();

                                modified |= columns[1]
                                    .add(Field::new(
                                        "EVA",
                                        egui::DragValue::new(&mut armor.eva).range(0..=i32::MAX),
                                    ))
                                    .changed();

                                modified |= columns[2]
                                    .add(Field::new(
                                        "PDEF",
                                        egui::DragValue::new(&mut armor.pdef).range(0..=i32::MAX),
                                    ))
                                    .changed();

                                modified |= columns[3]
                                    .add(Field::new(
                                        "MDEF",
                                        egui::DragValue::new(&mut armor.mdef).range(0..=i32::MAX),
                                    ))
                                    .changed();
                            });
                        });

                        ui.with_padded_stripe(true, |ui| {
                            ui.columns(4, |columns| {
                                modified |= columns[0]
                                    .add(Field::new(
                                        "STR+",
                                        egui::DragValue::new(&mut armor.str_plus),
                                    ))
                                    .changed();

                                modified |= columns[1]
                                    .add(Field::new(
                                        "DEX+",
                                        egui::DragValue::new(&mut armor.dex_plus),
                                    ))
                                    .changed();

                                modified |= columns[2]
                                    .add(Field::new(
                                        "AGI+",
                                        egui::DragValue::new(&mut armor.agi_plus),
                                    ))
                                    .changed();

                                modified |= columns[3]
                                    .add(Field::new(
                                        "INT+",
                                        egui::DragValue::new(&mut armor.int_plus),
                                    ))
                                    .changed();
                            });
                        });

                        ui.with_padded_stripe(false, |ui| {
                            ui.columns(2, |columns| {
                                let mut selection = IdVecSelection::new(
                                    update_state,
                                    (armor.id, "guard_element_set"),
                                    &mut armor.guard_element_set,
                                    1..system.elements.len(),
                                    |id| {
                                        system.elements.get(id).map_or_else(
                                            || "".into(),
                                            |e| format!("{id:0>4}: {}", e),
                                        )
                                    },
                                );
                                if self.previous_armor != Some(armor.id) {
                                    selection.clear_search();
                                }
                                modified |= columns[0]
                                    .add(Field::new("Element Defense", selection))
                                    .changed();

                                let mut selection = IdVecSelection::new(
                                    update_state,
                                    (armor.id, "guard_state_set"),
                                    &mut armor.guard_state_set,
                                    0..states.data.len(),
                                    |id| {
                                        states.data.get(id).map_or_else(
                                            || "".into(),
                                            |s| format!("{:0>4}: {}", id + 1, s.name),
                                        )
                                    },
                                );
                                if self.previous_armor != Some(armor.id) {
                                    selection.clear_search();
                                }
                                modified |=
                                    columns[1].add(Field::new("States", selection)).changed();
                            });
                        });

                        self.previous_armor = Some(armor.id);
                    },
                )
            });

        if response.is_some_and(|ir| ir.inner.is_some_and(|ir| ir.inner.modified)) {
            modified = true;
        }

        if modified {
            update_state.modified.set(true);
            armors.modified = true;
        }

        drop(armors);
        drop(system);
        drop(states);

        *update_state.data = data; // restore data
    }
}
