// src/tui/terminal/core.rs

use crossterm::{
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
    cursor::{SetCursorStyle, EnableBlinking, Show, Hide, MoveTo},
};
use ratatui::{backend::CrosstermBackend, Terminal};
use std::io::{self, stdout, Write};
use anyhow::Result;

pub struct TerminalCore {
    terminal: Terminal<CrosstermBackend<io::Stdout>>,
}

impl TerminalCore {
    pub fn new() -> Result<Self> {
        enable_raw_mode()?;
        let mut stdout = stdout();
        execute!(
            stdout,
            EnterAlternateScreen,
            SetCursorStyle::SteadyBlock,
            EnableBlinking
        )?;
        let backend = CrosstermBackend::new(stdout);
        let terminal = Terminal::new(backend)?;
        Ok(Self { terminal })
    }

    pub fn draw<F>(&mut self, f: F) -> Result<()>
    where
        F: FnOnce(&mut ratatui::Frame),
    {
        self.terminal.draw(f)?;
        Ok(())
    }

    pub fn cleanup(&mut self) -> Result<()> {
        let backend = self.terminal.backend_mut();
        execute!(
            backend,
            Show,
            SetCursorStyle::DefaultUserShape,
            LeaveAlternateScreen
        )?;
        disable_raw_mode()?;
        backend.flush()?;
        execute!(
            backend,
            crossterm::terminal::Clear(crossterm::terminal::ClearType::All),
            MoveTo(0, 0)
        )?;
        Ok(())
    }

    pub fn set_cursor_style(
        &mut self,
        style: SetCursorStyle,
    ) -> Result<()> {
        execute!(
            self.terminal.backend_mut(),
            style,
            EnableBlinking,
        )?;
        Ok(())
    }

    pub fn show_cursor(&mut self) -> Result<()> {
        execute!(
            self.terminal.backend_mut(),
            Show
        )?;
        Ok(())
    }

    pub fn hide_cursor(&mut self) -> Result<()> {
        execute!(
            self.terminal.backend_mut(),
            Hide
        )?;
        Ok(())
    }
}

impl Drop for TerminalCore {
    fn drop(&mut self) {
        let _ = self.cleanup();
    }
}
