//! Migrations tab — show applied/pending migrations.

use crossterm::event::{KeyCode, KeyEvent};
use ratatui::{
    layout::{Constraint, Rect},
    style::{Color, Modifier, Style},
    widgets::{Block, Borders, Cell, Row, Table, TableState},
    Frame,
};
use sqlx::PgPool;

use crate::app::AppAction;

pub struct MigrationEntry {
    pub version: String,
    pub applied: bool,
    pub applied_at: String,
}

pub struct MigrationsTab {
    pub items: Vec<MigrationEntry>,
    pub state: TableState,
    pub status: String,
}

impl Default for MigrationsTab {
    fn default() -> Self {
        Self {
            items: Vec::new(),
            state: TableState::default(),
            status: "Loading...".into(),
        }
    }
}

impl MigrationsTab {
    pub async fn load(&mut self, pool: &PgPool) {
        match fetch_migrations(pool).await {
            Ok(items) => {
                let applied = items.iter().filter(|m| m.applied).count();
                let pending = items.iter().filter(|m| !m.applied).count();
                self.status = format!("{applied} applied, {pending} pending");
                self.items = items;
                if self.state.selected().is_none() && !self.items.is_empty() {
                    self.state.select(Some(0));
                }
            }
            Err(e) => {
                self.status = format!("Error: {e}");
                self.items.clear();
            }
        }
    }

    pub fn render(&mut self, frame: &mut Frame, area: Rect) {
        let header = Row::new(vec![
            Cell::from("Status").style(Style::default().add_modifier(Modifier::BOLD)),
            Cell::from("Version").style(Style::default().add_modifier(Modifier::BOLD)),
            Cell::from("Applied At").style(Style::default().add_modifier(Modifier::BOLD)),
        ])
        .height(1);

        let rows: Vec<Row> = self
            .items
            .iter()
            .map(|m| {
                let (icon, color) = if m.applied {
                    ("✅", Color::Green)
                } else {
                    ("⏳", Color::Yellow)
                };
                Row::new(vec![
                    Cell::from(icon).style(Style::default().fg(color)),
                    Cell::from(m.version.as_str()),
                    Cell::from(m.applied_at.as_str()).style(Style::default().fg(Color::DarkGray)),
                ])
            })
            .collect();

        let widths = [
            Constraint::Length(4),
            Constraint::Min(30),
            Constraint::Length(22),
        ];

        let title = format!(" Migrations — {} ", self.status);
        let table = Table::new(rows, widths)
            .header(header)
            .block(Block::default().title(title).borders(Borders::ALL))
            .highlight_style(Style::default().bg(Color::DarkGray))
            .highlight_symbol("▶ ");

        frame.render_stateful_widget(table, area, &mut self.state);
    }

    pub fn handle_key(&mut self, key: KeyEvent) -> AppAction {
        match key.code {
            KeyCode::Up => {
                let i = self.state.selected().unwrap_or(0).saturating_sub(1);
                self.state.select(Some(i));
                AppAction::None
            }
            KeyCode::Down => {
                let max = self.items.len().saturating_sub(1);
                let i = (self.state.selected().unwrap_or(0) + 1).min(max);
                self.state.select(Some(i));
                AppAction::None
            }
            KeyCode::F(5) | KeyCode::Char('r') | KeyCode::Char('R') => AppAction::Reload,
            _ => AppAction::None,
        }
    }
}

async fn fetch_migrations(pool: &PgPool) -> anyhow::Result<Vec<MigrationEntry>> {
    use sqlx::Row as _;

    let rows = sqlx::query("SELECT version, applied_at FROM _migrations ORDER BY version")
        .fetch_all(pool)
        .await;

    match rows {
        Ok(rows) => Ok(rows
            .into_iter()
            .map(|r| {
                let applied_at_ts: Option<chrono::DateTime<chrono::Utc>> =
                    r.try_get("applied_at").ok();
                MigrationEntry {
                    version: r.try_get("version").unwrap_or_default(),
                    applied: true,
                    applied_at: applied_at_ts
                        .map(|t| t.format("%Y-%m-%d %H:%M:%S").to_string())
                        .unwrap_or_else(|| "-".into()),
                }
            })
            .collect()),
        Err(_) => Ok(vec![MigrationEntry {
            version: "(no _migrations table — run rok db:migrate first)".into(),
            applied: false,
            applied_at: String::new(),
        }]),
    }
}
