use tui_realm_stdlib::components::Input;
use tuirealm::command::{Cmd, CmdResult};
use tuirealm::component::Component;
use tuirealm::props::{
    AttrValue, Attribute, Borders, Color, HorizontalAlignment, QueryResult, Style, Table,
    TextModifiers, Title,
};
use tuirealm::ratatui::layout::{Constraint, Direction, Layout};
use tuirealm::state::State;

use super::file_list::FileList;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Focus {
    List,
    #[default]
    Search,
}

#[derive(Default)]
struct OwnStates {
    focus: Focus,
}

impl OwnStates {
    pub fn next(&mut self) {
        self.focus = match self.focus {
            Focus::List => Focus::Search,
            Focus::Search => Focus::List,
        };
    }
}

#[derive(Default)]
pub struct FileListWithSearch {
    file_list: FileList,
    search: Input,
    states: OwnStates,
}

impl FileListWithSearch {
    pub fn focus(&self) -> Focus {
        self.states.focus
    }

    pub fn foreground(mut self, fg: Color) -> Self {
        self.file_list
            .attr(Attribute::Foreground, AttrValue::Color(fg));
        self.search
            .attr(Attribute::Foreground, AttrValue::Color(fg));
        self
    }

    pub fn background(mut self, bg: Color) -> Self {
        self.file_list
            .attr(Attribute::Background, AttrValue::Color(bg));
        self.search
            .attr(Attribute::Background, AttrValue::Color(bg));
        self
    }

    pub fn borders(mut self, b: Borders) -> Self {
        self.file_list
            .attr(Attribute::Borders, AttrValue::Borders(b));
        self.search.attr(Attribute::Borders, AttrValue::Borders(b));
        self
    }

    pub fn title(mut self, t: Title) -> Self {
        let align = t.content.alignment.unwrap_or(HorizontalAlignment::Left);
        self.file_list.attr(Attribute::Title, AttrValue::Title(t));
        self.search.attr(
            Attribute::Title,
            AttrValue::Title(Title::from("Fuzzy search".to_string()).alignment(align)),
        );
        self
    }

    pub fn highlight_color(mut self, c: Color) -> Self {
        self.file_list.attr(
            Attribute::HighlightStyle,
            AttrValue::Style(Style::default().fg(c).add_modifier(TextModifiers::REVERSED)),
        );
        self
    }

    pub fn rows(mut self, rows: Table) -> Self {
        self.file_list
            .attr(Attribute::Content, AttrValue::Table(rows));
        self
    }
}

impl Component for FileListWithSearch {
    fn view(
        &mut self,
        frame: &mut tuirealm::ratatui::Frame,
        area: tuirealm::ratatui::layout::Rect,
    ) {
        // split the area in two
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Length(3), // Search
                    Constraint::Fill(1),   // File list
                ]
                .as_ref(),
            )
            .split(area);

        // render the search input
        self.search.view(frame, chunks[0]);
        // render the file list
        self.file_list.view(frame, chunks[1]);
    }

    fn query<'a>(&'a self, attr: Attribute) -> Option<QueryResult<'a>> {
        self.file_list.query(attr)
    }

    fn attr(&mut self, attr: Attribute, value: AttrValue) {
        if attr == Attribute::Focus {
            let value = value.unwrap_flag();
            match value {
                true => self.states.focus = Focus::Search,
                false => self.states.focus = Focus::List,
            }
            self.search.attr(
                Attribute::Focus,
                AttrValue::Flag(self.states.focus == Focus::Search),
            );
            self.file_list.attr(
                Attribute::Focus,
                AttrValue::Flag(self.states.focus == Focus::List),
            );
        } else {
            self.file_list.attr(attr, value);
        }
    }

    fn state(&self) -> State {
        match self.states.focus {
            Focus::List => self.file_list.state(),
            Focus::Search => self.search.state(),
        }
    }

    fn perform(&mut self, cmd: Cmd) -> CmdResult {
        match cmd {
            Cmd::Change => {
                self.states.next();
                self.search.attr(
                    Attribute::Focus,
                    AttrValue::Flag(self.states.focus == Focus::Search),
                );
                self.file_list.attr(
                    Attribute::Focus,
                    AttrValue::Flag(self.states.focus == Focus::List),
                );

                CmdResult::NoChange
            }
            cmd if self.states.focus == Focus::Search => self.search.perform(cmd),
            cmd => self.file_list.perform(cmd),
        }
    }
}
