mod config;
mod mangatab;
mod extensions;
use color_eyre::{Result};
use ratatui::{
    DefaultTerminal, buffer::Buffer, crossterm::event::{self, Event, KeyCode, KeyEventKind, KeyModifiers}, layout::{Constraint, Layout, Rect}, macros::horizontal, style::{Color, Stylize, palette::tailwind}, text::{Line, Text}, widgets::{Block, List, ListDirection, ListItem, Padding, Paragraph, Tabs, Widget}
};
use strum::{Display, EnumIter, FromRepr, IntoEnumIterator};
use crate::{mangatab::MangaTab, config::{getConfig, load_config, tailwindPaletteFromString}};

#[tokio::main]
async fn main() -> Result<()> {
    load_config();
    
    color_eyre::install()?;
    let terminal = ratatui::init();
    let app_result = App::default().run(terminal);
    ratatui::restore();
    app_result
}

#[derive(Default)]
struct App {
    state: AppState,
    selected_tab: SelectedTab
}

#[derive(Default, Clone, Copy, PartialEq, Eq)]
enum AppState {
    #[default]
    Running,
    Quitting,
}

#[derive(Default, Clone, Copy, Display, FromRepr, EnumIter)]
enum SelectedTab {
    #[default]
    #[strum(to_string = "Anime")]
    Tab1,
    #[strum(to_string = "Manga")]
    Tab2,
    #[strum(to_string = "Source")]
    Tab3,
    #[strum(to_string = "Settings")]
    Tab4,
}


impl App {
    fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
        while self.state == AppState::Running {
            terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;
            self.handle_events()?;
        }
        Ok(())
    }

    fn handle_events(&mut self) -> std::io::Result<()> {
        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                match key.code {
                    KeyCode::Esc => self.quit(),
                    _ => {}
                }
                if key.modifiers.contains(KeyModifiers::CONTROL) {
                    match key.code {
                        KeyCode::Char('c') => self.quit(),
                        _=>{}
                    }
                }
                if key.modifiers.contains(KeyModifiers::SHIFT) {   
                    match key.code {
                        KeyCode::Right => self.next_tab(),
                        KeyCode::Left => self.previous_tab(),
                        _ => {}
                    }
                } else {
                    
                }
            }
        }
        Ok(())
    }

    pub fn next_tab(&mut self) {
        self.selected_tab = self.selected_tab.next();
    }

    pub fn previous_tab(&mut self) {
        self.selected_tab = self.selected_tab.previous();
    }
    
    pub fn subnext_tab(&mut self) {
        self.selected_tab = self.selected_tab.subnext();
    }

    pub fn subprevious_tab(&mut self) {
        self.selected_tab = self.selected_tab.subprevious();
    }
    
    pub fn quit(&mut self) {
        self.state = AppState::Quitting;
    }
}

impl SelectedTab {
    /// Get the previous tab, if there is no previous tab return the current tab.
    fn previous(self) -> Self {
        let current_index: usize = self as usize;
        let previous_index = current_index.saturating_sub(1);
        Self::from_repr(previous_index).unwrap_or(self)
    }

    /// Get the next tab, if there is no next tab return the current tab.
    fn next(self) -> Self {
        let current_index = self as usize;
        let next_index = current_index.saturating_add(1);
        Self::from_repr(next_index).unwrap_or(self)
    }
    
}

impl Widget for &App {
    fn render(self, area: Rect, buf: &mut Buffer) {
        use Constraint::{Length, Min};
        let vertical = Layout::vertical([Length(1), Min(0), Length(1)]);
        let [header_area, inner_area, footer_area] = vertical.areas(area);

        let horizontal = Layout::horizontal([Min(0), Length(20)]);
        let [tabs_area, title_area] = horizontal.areas(header_area);

        render_title(title_area, buf);
        self.render_tabs(tabs_area, buf);
        self.selected_tab.render(inner_area, buf);
        render_footer(footer_area, buf);
    }
}

impl App {
    fn render_tabs(&self, area: Rect, buf: &mut Buffer) {
        let titles = SelectedTab::iter().map(SelectedTab::title);
        let highlight_style = (Color::default(), self.selected_tab.palette().c700);
        let selected_tab_index = self.selected_tab as usize;
        Tabs::new(titles)
            .highlight_style(highlight_style)
            .select(selected_tab_index)
            .padding("", "")
            .divider(" ")
            .render(area, buf);
    }
}

fn render_title(area: Rect, buf: &mut Buffer) {
    "Anime&Manga Scraper CLI".bold().render(area, buf);
}

fn render_footer(area: Rect, buf: &mut Buffer) {
    Line::raw("Shift + ArrowKeys to choose the Tab | Press ESC to quit")
        .centered()
        .render(area, buf);
}

impl Widget for SelectedTab {
    fn render(self, area: Rect, buf: &mut Buffer) {
        // in a real app these might be separate widgets
        match self {
            Self::Tab1 => self.render_Anime(area, buf),
            Self::Tab2 => self.render_Manga(area, buf),
            Self::Tab3 => self.render_Sources(area, buf),
            Self::Tab4 => self.render_Settings(area, buf),
        }
    }
}

impl SelectedTab {
    /// Return tab's name as a styled `Line`
    fn title(self) -> Line<'static> {
        format!("  {self}  ")
            .fg(tailwind::SLATE.c200)
            // .bg(self.palette().c900)
            .into()
    }

    fn render_Anime(self, area: Rect, buf: &mut Buffer) {
        Paragraph::new("Anime Home Library: View saved and search for new one in all sources")
            .block(self.block())
            .render(area, buf);
    }

    fn render_Manga(self, area: Rect, buf: &mut Buffer) {
        // Paragraph::new("Manga  Home Library: View saved and search for new one in all sources")
        //     .block(self.block())
        //     .render(area, buf);
        // INNER TAB FOR OPTIONS
        let titles = MangaTab::iter().map(MangaTab::title);
        let highlight_style = (Color::default(), self.selected_tab.palette().c700);
        let selected_tab_index = self.selected_tab as usize;
        Tabs::new(titles)
            .highlight_style(highlight_style)
            .select(selected_tab_index)
            .padding("", "")
            .divider(" ")
            .render(area, buf);
    }   
    fn render_Sources(self, area: Rect, buf: &mut Buffer) {
        Paragraph::new("Sources to source the web")
            .block(self.block())
            .render(area, buf);
    }
    
    fn render_Settings(self, area: Rect, buf: &mut Buffer) {
        Paragraph::new("For now just credits")
            .block(self.block())
            .render(area, buf);
    }
    

    /// A block surrounding the tab's content
    fn block(self) -> Block<'static> {
        Block::bordered()
            .padding(Padding::horizontal(1))
            .border_style(self.palette().c500)
    }

    fn palette(self) -> tailwind::Palette {
        match self {
            Self::Tab1 => tailwindPaletteFromString(&getConfig().Customization.ColorPalette.anime,tailwind::PURPLE),
            Self::Tab2 => tailwindPaletteFromString(&getConfig().Customization.ColorPalette.manga,tailwind::AMBER),
            Self::Tab3 => tailwindPaletteFromString(&getConfig().Customization.ColorPalette.source,tailwind::EMERALD),
            Self::Tab4 => tailwindPaletteFromString(&getConfig().Customization.ColorPalette.settings,tailwind::RED),
        }
    }
}