#![allow(dead_code)] // Phase 1: screen content renders added in Phase 2+

//! Top-level view dispatch for the lore TUI.
//!
//! [`render_screen`] is the entry point called from `LoreApp::view()`.
//! It composes the layout: breadcrumb bar, screen content area, status
//! bar, and optional overlays (help, error toast).

pub mod bootstrap;
pub mod command_palette;
pub mod common;
pub mod dashboard;
pub mod doctor;
pub mod file_history;
pub mod issue_detail;
pub mod issue_list;
pub mod mr_detail;
pub mod mr_list;
pub mod scope_picker;
pub mod search;
pub mod stats;
pub mod sync;
pub mod timeline;
pub mod trace;
pub mod who;

use ftui::layout::{Constraint, Flex};
use ftui::render::cell::PackedRgba;
use ftui::render::frame::Frame;

use crate::app::LoreApp;
use crate::message::Screen;

use bootstrap::render_bootstrap;
use command_palette::render_command_palette;
use common::{
    render_breadcrumb, render_error_toast, render_help_overlay, render_loading, render_status_bar,
};
use dashboard::render_dashboard;
use doctor::render_doctor;
use file_history::render_file_history;
use issue_detail::render_issue_detail;
use issue_list::render_issue_list;
use mr_detail::render_mr_detail;
use mr_list::render_mr_list;
use scope_picker::render_scope_picker;
use search::render_search;
use stats::render_stats;
use sync::render_sync;
use timeline::render_timeline;
use trace::render_trace;
use who::render_who;

// ---------------------------------------------------------------------------
// Colors (hardcoded Flexoki palette — will use Theme in Phase 2)
// ---------------------------------------------------------------------------

const TEXT: PackedRgba = PackedRgba::rgb(0xCE, 0xCD, 0xC3); // tx
const TEXT_MUTED: PackedRgba = PackedRgba::rgb(0x87, 0x87, 0x80); // tx-2
const BG_SURFACE: PackedRgba = PackedRgba::rgb(0x28, 0x28, 0x24); // bg-2
const ACCENT: PackedRgba = PackedRgba::rgb(0xDA, 0x70, 0x2C); // orange
const ERROR_BG: PackedRgba = PackedRgba::rgb(0xAF, 0x3A, 0x29); // red
const ERROR_FG: PackedRgba = PackedRgba::rgb(0xCE, 0xCD, 0xC3); // tx
const BORDER: PackedRgba = PackedRgba::rgb(0x87, 0x87, 0x80); // tx-2

// ---------------------------------------------------------------------------
// render_screen
// ---------------------------------------------------------------------------

/// Top-level view dispatch: composes breadcrumb + content + status bar + overlays.
///
/// Called from `LoreApp::view()`. The layout is:
/// ```text
/// +-----------------------------------+
/// | Breadcrumb (1 row)                |
/// +-----------------------------------+
/// |                                   |
/// | Screen content (fill)             |
/// |                                   |
/// +-----------------------------------+
/// | Status bar (1 row)                |
/// +-----------------------------------+
/// ```
///
/// Overlays (help, error toast) render on top of existing content.
pub fn render_screen(frame: &mut Frame<'_>, app: &LoreApp) {
    let bounds = frame.bounds();
    if bounds.width < 3 || bounds.height < 3 {
        return; // Terminal too small to render anything useful.
    }

    // Split vertically: breadcrumb (1) | content (fill) | status bar (1).
    let regions = Flex::vertical()
        .constraints([
            Constraint::Fixed(1), // breadcrumb
            Constraint::Fill,     // content
            Constraint::Fixed(1), // status bar
        ])
        .split(bounds);

    let breadcrumb_area = regions[0];
    let content_area = regions[1];
    let status_area = regions[2];

    let screen = app.navigation.current();

    // --- Breadcrumb ---
    render_breadcrumb(frame, breadcrumb_area, &app.navigation, TEXT, TEXT_MUTED);

    // --- Screen content ---
    let load_state = app.state.load_state.get(screen);
    // tick=0 placeholder — animation wired up when Msg::Tick increments a counter.
    render_loading(frame, content_area, load_state, TEXT, TEXT_MUTED, 0);

    // Per-screen content dispatch (other screens wired in later phases).
    if screen == &Screen::Bootstrap {
        render_bootstrap(frame, &app.state.bootstrap, content_area);
    } else if screen == &Screen::Sync {
        render_sync(frame, &app.state.sync, content_area);
    } else if screen == &Screen::Dashboard {
        render_dashboard(frame, &app.state.dashboard, content_area);
    } else if screen == &Screen::IssueList {
        render_issue_list(frame, &app.state.issue_list, content_area);
    } else if screen == &Screen::MrList {
        render_mr_list(frame, &app.state.mr_list, content_area);
    } else if matches!(screen, Screen::IssueDetail(_)) {
        render_issue_detail(frame, &app.state.issue_detail, content_area, &*app.clock);
    } else if matches!(screen, Screen::MrDetail(_)) {
        render_mr_detail(frame, &app.state.mr_detail, content_area, &*app.clock);
    } else if screen == &Screen::Search {
        render_search(frame, &app.state.search, content_area);
    } else if screen == &Screen::Timeline {
        render_timeline(frame, &app.state.timeline, content_area, &*app.clock);
    } else if screen == &Screen::Who {
        render_who(frame, &app.state.who, content_area);
    } else if screen == &Screen::FileHistory {
        render_file_history(frame, &app.state.file_history, content_area);
    } else if screen == &Screen::Trace {
        render_trace(frame, &app.state.trace, content_area);
    } else if screen == &Screen::Doctor {
        render_doctor(frame, &app.state.doctor, content_area);
    } else if screen == &Screen::Stats {
        render_stats(frame, &app.state.stats, content_area);
    }

    // --- Status bar ---
    render_status_bar(
        frame,
        status_area,
        &app.command_registry,
        screen,
        &app.input_mode,
        BG_SURFACE,
        TEXT,
        ACCENT,
    );

    // --- Overlays (render last, on top of everything) ---

    // Error toast.
    if let Some(ref error_msg) = app.state.error_toast {
        render_error_toast(frame, bounds, error_msg, ERROR_BG, ERROR_FG);
    }

    // Command palette overlay.
    render_command_palette(frame, &app.state.command_palette, bounds);

    // Scope picker overlay.
    render_scope_picker(
        frame,
        &app.state.scope_picker,
        &app.state.global_scope,
        bounds,
    );

    // Help overlay.
    if app.state.show_help {
        render_help_overlay(
            frame,
            bounds,
            &app.command_registry,
            screen,
            BORDER,
            TEXT,
            TEXT_MUTED,
            0, // scroll_offset — tracked in future phase
        );
    }
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::app::LoreApp;
    use ftui::render::grapheme_pool::GraphemePool;

    macro_rules! with_frame {
        ($width:expr, $height:expr, |$frame:ident| $body:block) => {{
            let mut pool = GraphemePool::new();
            let mut $frame = Frame::new($width, $height, &mut pool);
            $body
        }};
    }

    #[test]
    fn test_render_screen_does_not_panic() {
        with_frame!(80, 24, |frame| {
            let app = LoreApp::new();
            render_screen(&mut frame, &app);
        });
    }

    #[test]
    fn test_render_screen_tiny_terminal_noop() {
        with_frame!(2, 2, |frame| {
            let app = LoreApp::new();
            render_screen(&mut frame, &app);
            // Should not panic — early return for tiny terminals.
        });
    }

    #[test]
    fn test_render_screen_with_error_toast() {
        with_frame!(80, 24, |frame| {
            let mut app = LoreApp::new();
            app.state.set_error("test error".into());
            render_screen(&mut frame, &app);
            // Should render without panicking.
        });
    }

    #[test]
    fn test_render_screen_with_help_overlay() {
        with_frame!(80, 24, |frame| {
            let mut app = LoreApp::new();
            app.state.show_help = true;
            render_screen(&mut frame, &app);
            // Should render without panicking.
        });
    }

    #[test]
    fn test_render_screen_narrow_terminal() {
        with_frame!(20, 5, |frame| {
            let app = LoreApp::new();
            render_screen(&mut frame, &app);
        });
    }

    #[test]
    fn test_render_screen_sync_has_content() {
        with_frame!(80, 24, |frame| {
            let mut app = LoreApp::new();
            app.navigation.push(Screen::Sync);
            render_screen(&mut frame, &app);

            let has_content = (20..60u16).any(|x| {
                (8..16u16).any(|y| frame.buffer.get(x, y).is_some_and(|cell| !cell.is_empty()))
            });
            assert!(has_content, "Expected sync idle content in center area");
        });
    }
}
