use std::cell::RefCell;

use crate::card::Card;
use crate::db::{get_db_path, get_images_store_path};
use crate::widgets::card_display::*;

use glib::subclass::InitializingObject;
use gtk::glib::clone;
use gtk::subclass::prelude::*;
use gtk::{glib, Box, Button, CompositeTemplate, Label};
use gtk::{prelude::*, Entry};
use rusqlite::Connection;

#[derive(CompositeTemplate, Default)]
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/game/ui.xml")]
pub struct MemoryCardsGameScene {
    #[template_child]
    pub card_display: TemplateChild<CardDisplay>,
    #[template_child]
    pub stats_label: TemplateChild<Label>,
    #[template_child]
    pub content: TemplateChild<Box>,
    #[template_child]
    pub no_cards_label: TemplateChild<Label>,
    #[template_child]
    pub back_button: TemplateChild<Button>,

    pub correct: RefCell<usize>,
    pub incorrect: RefCell<usize>,
}

#[glib::object_subclass]
impl ObjectSubclass for MemoryCardsGameScene {
    const NAME: &'static str = "MemoryCardsGameScene";
    type Type = super::MemoryCardsGameScene;
    type ParentType = gtk::ApplicationWindow;

    fn class_init(klass: &mut Self::Class) {
        klass.bind_template();
    }

    fn instance_init(obj: &InitializingObject<Self>) {
        obj.init_template();
    }
}

impl ObjectImpl for MemoryCardsGameScene {
    fn constructed(&self) {
        self.parent_constructed();

        let card_display_binding = self.card_display.imp().obj();
        let self_binding = self.obj();

        self.update_card();

        card_display_binding.get_answer_entry().connect_activate(clone!(@strong card_display_binding, @strong self_binding  => move |e: &Entry| {
            card_display_binding.imp().incorrect_message.set_visible(false);
            let incorrect_message_label = &card_display_binding.imp().incorrect_message;
            if e.text() == *card_display_binding.hieroglyph() {
                *self_binding.imp().correct.borrow_mut() += 1;
                incorrect_message_label.set_visible(false);
            } else {
                *self_binding.imp().incorrect.borrow_mut() +=1;
                incorrect_message_label.set_visible(true);
                let message = format!("Incorrect! It was {} reading as {} with meaning {}", card_display_binding.hieroglyph(), card_display_binding.reading(), card_display_binding.translation());
                incorrect_message_label.set_label(&message);
            }
            self_binding.update_stats();
            self_binding.imp().update_card();
            e.set_text("");
        }));
    }
}

impl MemoryCardsGameScene {
    pub fn update_card(&self) {
        match generate_card() {
            Some(card) => {
                self.card_display.set_imagepath(card.imagepath());
                self.card_display.set_hieroglyph(card.hieroglyph());
                self.card_display.set_reading(card.reading());
                self.card_display.set_translation(card.translation());
                self.card_display.update_file_for_image();
                self.obj().hide_no_cards_msg();
            }
            None => self.obj().show_no_cards_msg(),
        }
    }
}

fn generate_card() -> Option<CardDisplay> {
    let connection = Connection::open(get_db_path()).unwrap();

    let mut stmt = connection.prepare("SELECT imagename, hieroglyph, reading, translation FROM cards WHERE is_learning = TRUE AND imagename != '' ORDER BY RANDOM() LIMIT 1").unwrap();
    let random_card_iter = stmt
        .query_map((), |row| {
            Ok(Card::new(
                row.get(0).unwrap(),
                row.get(1).unwrap(),
                row.get(2).unwrap(),
                row.get(3).unwrap(),
                Some(true),
            ))
        })
        .unwrap();

    let mut random_card = None;
    for i in random_card_iter {
        random_card = Some(i.unwrap());
    }
    let random_card: Card = match random_card {
        Some(card) => card,
        None => return None,
    };

    let generated_card = CardDisplay::new(
        &(get_images_store_path()
            + "/"
            + match &random_card.image_path() {
                Some(path) => path,
                None => return None,
            }),
        &random_card.hieroglyph().unwrap(),
        Some(&random_card.reading().unwrap()),
        &random_card.translation().unwrap(),
    );

    Some(generated_card)
}

impl WidgetImpl for MemoryCardsGameScene {}

impl WindowImpl for MemoryCardsGameScene {}

impl ApplicationWindowImpl for MemoryCardsGameScene {}
