use crate::data_provider::words::{delete_word, update_word};
use crate::lang::WordData;
use crate::navigation::Page::PreviousPage;
use crate::navigation::{NavigatedPage, Page};
use crate::styling::*;
use crate::word::WordMessage::*;
use crate::{AppState, RootMessage};
use iced::widget::button::danger;
use iced::widget::{button, column, row, rule, scrollable, text, text_input};
use iced::{Element, Fill, Task};
use std::sync::Arc;
use parking_lot::Mutex;

#[derive(Clone)]
pub struct WordState {
    state: Arc<Mutex<AppState>>,
    index: usize,
    word: WordData,
}

impl NavigatedPage<WordMessage> for WordState {
    fn navigate(&mut self, message: &WordMessage) -> Option<Page> {
        if let Back = message {
            Some(PreviousPage)
        } else {
            None
        }
    }

    fn navigated(&mut self) {}
    fn update(&mut self, message: WordMessage) -> Task<RootMessage> {
        match message {
            Back => {}
            Save => {
                let mut state = self.state.lock();
                state.dictionary[self.index] = self.word.clone();
                update_word(&mut self.word, &state.connection);
                return Task::done(RootMessage::Word(Back));
            }
            Delete => {
                let mut state = self.state.lock();
                state.dictionary.remove(self.index);
                delete_word(&self.word, &state.connection);
                return Task::done(RootMessage::Word(Back));
            }
            SetTags(n) => self.word.tags = n,
            SetKey(n) => {
                self.word.key = n;
            }
            SetValue(n) => {
                self.word.value = n;
            }
            SetAdditional(key, value) => {
                self.word.additional.insert(key, value.clone());
            }
            AddAdditional(key) => {
                self.word.additional.insert(key, "".to_string());
            }
            RemoveAdditional(key) => {
                self.word.additional.remove(key.as_str());
            }
        }
        Task::none()
    }

    fn view(&self) -> Element<'_, WordMessage> {
        let mut fast_add = row![];
        if !self.word.additional.contains_key("reading") {
            fast_add = fast_add.push(
                button("Чтение")
                    .style(button::text)
                    .on_press(AddAdditional("reading".to_string())),
            );
        }
        if !self.word.additional.contains_key("description") {
            fast_add = fast_add.push(
                button("Описание")
                    .style(button::text)
                    .on_press(AddAdditional("description".to_string())),
            );
        }

        if !self.word.additional.contains_key("context") {
            fast_add = fast_add.push(
                button("В контексте")
                    .style(button::text)
                    .on_press(AddAdditional("context".to_string())),
            );
        }

        let mut col = iced::widget::column![
            column![
                text!("Ключ"),
                text_input("key", &self.word.key).on_input(SetKey),
            ]
            .spacing(QUARTER_SPACING),
            column![
                text!("Значение"),
                text_input("value", &self.word.value).on_input(SetValue),
            ]
            .spacing(QUARTER_SPACING),
            column![
                text!("Теги"),
                text_input("tags", &self.word.tags).on_input(SetTags),
            ]
            .spacing(QUARTER_SPACING),
            rule::horizontal(2),
            scrollable(fast_add),
        ];

        for more in &self.word.additional {
            col = col.push(self.get_view_for_more(more));
        }

        back_overlay(
            column![
                col.spacing(DEFAULT_SPACING / 2.0).width(Fill).height(Fill),
                row![
                    button("Сохранить").style(jl_button).on_press(Save),
                    button("Удалить").style(danger).on_press(Delete),
                ]
                .spacing(DEFAULT_SPACING)
            ]
            .spacing(DEFAULT_SPACING)
            .into(),
            Back,
        )
    }
}

impl WordState {
    pub(crate) fn new(word: WordData, index: usize, state: Arc<Mutex<AppState>>) -> WordState {
        WordState { state, index, word }
    }
}

impl WordState {
    fn get_view_for_more(&self, value: (&String, &String)) -> Element<'_, WordMessage> {
        match value.0.as_str() {
            "reading" => self.reading_field(value.1),
            "description" => self.description_field(value.1),
            "context" => self.context_field(value.1),
            _ => self.additional_field(value.1, value.0.clone(), value.0.clone()),
        }
    }

    fn reading_field(&self, value: &str) -> Element<'_, WordMessage> {
        self.additional_field(value, "Чтение слова".to_string(), "reading".to_string())
    }

    fn description_field(&self, value: &str) -> Element<'_, WordMessage> {
        self.additional_field(value, "Описание".to_string(), "description".to_string())
    }

    fn context_field(&self, value: &str) -> Element<'_, WordMessage> {
        self.additional_field(value, "В контексте".to_string(), "context".to_string())
    }
    fn additional_field(&self, value: &str, name: String, id: String) -> Element<'_, WordMessage> {
        column![
            text!("{}", name),
            row![
                text_input(id.clone().as_str(), value)
                    .on_input({
                        let value = id.clone();
                        move |string| SetAdditional(value.clone(), string)
                    })
                    .width(Fill),
                button("-")
                    .on_press(RemoveAdditional(id.clone()))
                    .style(danger),
            ]
            .spacing(QUARTER_SPACING),
        ]
        .spacing(QUARTER_SPACING)
        .into()
    }
}

#[derive(Debug, Clone)]
pub enum WordMessage {
    Save,
    Back,
    Delete,
    SetTags(String),
    SetKey(String),
    SetValue(String),
    AddAdditional(String),
    RemoveAdditional(String),
    SetAdditional(String, String),
}
