use crate::domain::events::presentation_events::NavigateTo;
use crate::domain::events::EventBusInterface;
use crate::domain::services::theme_service::ThemeServiceInterface;
use crate::infrastructure::logging::get_current_log_file_path;
use crate::presentation::tui::{Screen, ScreenDataProvider, ScreenType, UpdateStrategy};
use crate::presentation::ui::Colors;
use crate::Result;
use ratatui::{
    layout::{Alignment, Constraint, Direction, Layout},
    style::Style,
    text::{Line, Span},
    widgets::{Block, Borders, Padding, Paragraph, Wrap},
    Frame,
};
use std::sync::{Arc, RwLock};

pub trait PanicScreenInterface: Screen {}

#[derive(shaku::Component)]
#[shaku(interface = PanicScreenInterface)]
pub struct PanicScreen {
    #[shaku(default)]
    error_message: RwLock<String>,
    #[shaku(default)]
    timestamp: RwLock<String>,
    #[shaku(inject)]
    event_bus: Arc<dyn EventBusInterface>,
    #[shaku(inject)]
    theme_service: Arc<dyn ThemeServiceInterface>,
}

impl PanicScreen {
    pub fn new(
        event_bus: Arc<dyn EventBusInterface>,
        theme_service: Arc<dyn ThemeServiceInterface>,
    ) -> Self {
        Self {
            error_message: RwLock::new("An unexpected error occurred".to_string()),
            timestamp: RwLock::new(Self::get_current_timestamp()),
            event_bus,
            theme_service,
        }
    }

    pub fn with_error_message(
        error_message: String,
        event_bus: Arc<dyn EventBusInterface>,
        theme_service: Arc<dyn ThemeServiceInterface>,
        timestamp: Option<String>,
    ) -> Self {
        Self {
            error_message: RwLock::new(error_message),
            timestamp: RwLock::new(timestamp.unwrap_or_else(Self::get_current_timestamp)),
            event_bus,
            theme_service,
        }
    }

    fn get_current_timestamp() -> String {
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| {
                let secs = d.as_secs();
                let dt = std::time::UNIX_EPOCH + std::time::Duration::from_secs(secs);
                format!("{:?}", dt)
            })
            .unwrap_or_else(|_| "Unknown time".to_string())
    }

    fn render_panic_content(&self, frame: &mut Frame, colors: &Colors) {
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Length(3), // Header
                Constraint::Length(3), // Apology message
                Constraint::Length(9), // Help info
                Constraint::Min(6),    // Error details (flexible)
                Constraint::Length(1), // ESC key (no border)
            ])
            .split(frame.area());

        // Render header (no border)
        let header_lines = vec![Line::from(""), Line::from("💥 APPLICATION PANIC 💥")];
        let header = Paragraph::new(header_lines)
            .style(Style::default().fg(colors.error()))
            .alignment(Alignment::Center);
        frame.render_widget(header, chunks[0]);

        // Render apology message (no border)
        let apology_lines = vec![
            Line::from(Span::styled(
                "We sincerely apologize for this unexpected error.",
                Style::default().fg(colors.error()),
            )),
            Line::from(Span::styled(
                "Progress is saved per session. Current session data may be lost.",
                Style::default().fg(colors.warning()),
            )),
        ];
        let apology_widget = Paragraph::new(apology_lines).alignment(Alignment::Center);
        frame.render_widget(apology_widget, chunks[1]);

        // Render help information
        let log_path = get_current_log_file_path()
            .unwrap_or_else(|| "~/.gittype/logs/gittype_YYYYMMDD_HHMMSS.log".to_string());

        let help_lines = vec![
            Line::from(""),
            Line::from(Span::styled(
                "📋 Logs saved to:",
                Style::default().fg(colors.success()),
            )),
            Line::from(Span::raw(log_path)),
            Line::from(""),
            Line::from(Span::styled(
                "🐛 Report this issue:",
                Style::default().fg(colors.stage_info()),
            )),
            Line::from(Span::raw("https://github.com/unhappychoice/gittype/issues")),
            Line::from(""),
        ];

        let help_widget = Paragraph::new(help_lines)
            .alignment(Alignment::Center)
            .block(Block::default().borders(Borders::ALL).title("Help"));
        frame.render_widget(help_widget, chunks[2]);

        // Render detailed error info
        let timestamp = self.timestamp.read().unwrap();
        let error_message = self.error_message.read().unwrap();

        let mut error_lines = vec![
            Line::from(Span::styled("Time:", Style::default().fg(colors.info()))),
            Line::from(Span::raw(timestamp.as_str())),
            Line::from(""),
            Line::from(Span::styled(
                "Panic Message:",
                Style::default().fg(colors.error()),
            )),
        ];

        // Add error message lines (split for better readability)
        for line in error_message.lines() {
            // Check if this line contains Location info and format it properly
            if line.trim().starts_with("Location:") {
                error_lines.push(Line::from(""));
                error_lines.push(Line::from(Span::styled(
                    "Location:",
                    Style::default().fg(colors.info()),
                )));
                let location_info = line.trim().strip_prefix("Location:").unwrap_or("").trim();
                error_lines.push(Line::from(location_info));
            } else {
                error_lines.push(Line::from(line));
            }
        }

        let error_info = Paragraph::new(error_lines)
            .alignment(Alignment::Left)
            .wrap(Wrap { trim: true })
            .block(
                Block::default()
                    .borders(Borders::ALL)
                    .title("Error Details")
                    .padding(Padding::uniform(1)),
            );
        frame.render_widget(error_info, chunks[3]);

        // Render ESC key at the bottom (no border, consistent with other screens)
        let esc_instruction = Paragraph::new(Line::from(vec![
            Span::styled("[ESC]", Style::default().fg(colors.key_back())),
            Span::raw(" Exit"),
        ]))
        .alignment(Alignment::Center);
        frame.render_widget(esc_instruction, chunks[4]);
    }
}

pub struct PanicScreenDataProvider;

impl ScreenDataProvider for PanicScreenDataProvider {
    fn provide(&self) -> Result<Box<dyn std::any::Any>> {
        Ok(Box::new(()))
    }
}

pub struct PanicScreenProvider;

impl shaku::Provider<crate::presentation::di::AppModule> for PanicScreenProvider {
    type Interface = PanicScreen;

    fn provide(
        module: &crate::presentation::di::AppModule,
    ) -> std::result::Result<Box<Self::Interface>, Box<dyn std::error::Error>> {
        use shaku::HasComponent;
        let event_bus: Arc<dyn EventBusInterface> = module.resolve();
        let theme_service: Arc<dyn ThemeServiceInterface> = module.resolve();
        Ok(Box::new(PanicScreen::new(event_bus, theme_service)))
    }
}

impl Screen for PanicScreen {
    fn get_type(&self) -> ScreenType {
        ScreenType::Panic
    }

    fn default_provider() -> Box<dyn ScreenDataProvider>
    where
        Self: Sized,
    {
        Box::new(PanicScreenDataProvider)
    }

    fn init_with_data(&self, _data: Box<dyn std::any::Any>) -> Result<()> {
        Ok(())
    }

    fn handle_key_event(&self, key_event: crossterm::event::KeyEvent) -> Result<()> {
        use crossterm::event::KeyCode;
        match key_event.code {
            KeyCode::Esc => {
                self.event_bus.as_event_bus().publish(NavigateTo::Exit);
                Ok(())
            }
            _ => Ok(()),
        }
    }

    fn render_ratatui(&self, frame: &mut Frame) -> Result<()> {
        let colors = self.theme_service.get_colors();
        self.render_panic_content(frame, &colors);
        Ok(())
    }

    fn get_update_strategy(&self) -> UpdateStrategy {
        UpdateStrategy::InputOnly
    }

    fn update(&self) -> Result<bool> {
        Ok(false)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

impl PanicScreenInterface for PanicScreen {}
