use crate::db::Database;
use crate::models::{AppState, Status, Task};
use ratatui::widgets::{ListState, TableState};
use std::error::Error;

pub struct App {
    pub db: Database,
    pub tasks: Vec<Task>,
    pub table_state: TableState,
    pub list_status_state: ListState,
    pub status_list: [&'static str; 4],
    pub app_state: AppState,
    pub name_input: String,
    pub status_input: String,
    pub current_page: u32,
    pub page_size: u32,
    pub total_count: u32,
}

impl App {
    pub fn new(db_path: &str) -> Result<Self, Box<dyn Error>> {
        Self::with_page_size(db_path, 50)
    }

    pub fn with_page_size(db_path: &str, size: u32) -> Result<Self, Box<dyn Error>> {
        let db = Database::new(db_path)?;
        let count = db.count_tasks()?;
        let tasks = db.get_tasks_paginated(0, size)?;
        let mut table_state = TableState::default();
        let list_state = ListState::default();

        if !tasks.is_empty() {
            table_state.select(Some(0));
        }

        Ok(App {
            db,
            tasks,
            table_state,
            list_status_state: list_state,
            status_list: [
                Status::Selected.as_ref(),
                Status::WIP.as_ref(),
                Status::Revision.as_ref(),
                Status::Done.as_ref(),
            ],
            app_state: AppState::Normal,
            name_input: String::new(),
            status_input: String::new(),
            current_page: 0,
            page_size: size,
            total_count: count,
        })
    }

    pub fn refresh_task(&mut self) -> Result<(), Box<dyn Error>> {
        self.total_count = self.db.count_tasks()?;
        self.tasks = self
            .db
            .get_tasks_paginated(self.current_page, self.page_size)?;

        if self.tasks.is_empty() {
            self.table_state.select(None);
        } else if let Some(selected) = self.table_state.selected() {
            if selected >= self.tasks.len() {
                self.table_state.select(Some(self.tasks.len() - 1));
            }
        } else if !self.tasks.is_empty() {
            self.table_state.select(Some(0));
        }

        Ok(())
    }

    pub fn next_page(&mut self) -> Result<(), Box<dyn Error>> {
        let max_page = (self.total_count.saturating_sub(1)) / self.page_size;
        if self.current_page < max_page {
            self.current_page += 1;
            self.refresh_task()?;
            self.table_state.select(Some(0));
        }
        Ok(())
    }

    pub fn prev_page(&mut self) -> Result<(), Box<dyn Error>> {
        if self.current_page > 0 {
            self.current_page -= 1;
            self.refresh_task()?;
            self.table_state.select(Some(0));
        }
        Ok(())
    }

    pub fn total_pages(&self) -> u32 {
        if self.total_count == 0 {
            1
        } else {
            self.total_count.div_ceil(self.page_size)
        }
    }

    pub fn pagination_info(&self) -> String {
        format!(
            "Page {}/{} | Total: {} | Showing: {}",
            self.current_page + 1,
            self.total_pages(),
            self.total_count,
            self.tasks.len()
        )
    }

    pub fn next(&mut self) {
        if self.tasks.is_empty() {
            return;
        }

        let i = match self.table_state.selected() {
            Some(i) => {
                if i >= self.tasks.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.table_state.select(Some(i));
    }

    pub fn previous(&mut self) {
        if self.tasks.is_empty() {
            return;
        }

        let i = match self.table_state.selected() {
            Some(i) => {
                if i == 0 {
                    self.tasks.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.table_state.select(Some(i));
    }

    pub fn increase_story_points(&mut self) -> Result<(), Box<dyn Error>> {
        if let Some(i) = self.table_state.selected()
            && let Some(task) = self.tasks.get(i)
        {
            let points = task.story_points + 1;
            self.db.update_story_point(task.id, points.to_string())?;
        }
        Ok(())
    }

    pub fn decrease_story_points(&mut self) -> Result<(), Box<dyn Error>> {
        if let Some(i) = self.table_state.selected()
            && let Some(task) = self.tasks.get(i)
        {
            let points = task.story_points - 1;
            self.db.update_story_point(task.id, points.to_string())?;
        }
        Ok(())
    }

    pub fn change_status(&mut self) -> Result<(), Box<dyn Error>> {
        if let Some(i) = self.table_state.selected()
            && let Some(task) = self.tasks.get(i)
        {
            if let Some(s) = self.list_status_state.selected()
                && let Some(st) = self.status_list.get(s)
            {
                let st: Status = st.parse().unwrap();
                self.db.update_status(task.id, st)?;
            }
        }
        Ok(())
    }

    pub fn add_task(&mut self) -> Result<(), Box<dyn Error>> {
        if !self.name_input.trim().is_empty() {
            self.db.add_task(&self.name_input, Status::Selected)?;
            self.name_input.clear();
            self.refresh_task()?;
        }
        Ok(())
    }

    pub fn enter_edit_mode(&mut self) {
        self.app_state = AppState::Editing;
    }

    pub fn exit_edit_mode(&mut self) {
        self.app_state = AppState::Normal;
    }

    pub fn input_char(&mut self, c: char) {
        self.name_input.push(c);
    }

    pub fn input_backspace(&mut self) {
        self.name_input.pop();
    }

    pub fn next_status(&mut self) {
        let i = match self.list_status_state.selected() {
            Some(i) => {
                if i >= self.status_list.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.list_status_state.select(Some(i));
    }

    pub fn previous_status(&mut self) {
        let i = match self.list_status_state.selected() {
            Some(i) => {
                if i == 0 {
                    self.status_list.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.list_status_state.select(Some(i));
    }

    pub fn exit_status_mode(&mut self) {
        self.app_state = AppState::Normal;
    }

    pub fn enter_status_mode(&mut self) {
        self.app_state = AppState::SelectStatus;
    }
}
