mod tdlib;

use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
    backend::CrosstermBackend,
    layout::{Alignment, Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, List, ListItem, ListState, Paragraph},
    Frame, Terminal,
};
use std::ffi::CString;
use std::io;
use std::os::raw::c_char;
use std::sync::mpsc;
use std::time::Duration;
use tdlib::client::{AuthState, ChatInfo, MessageInfo};
use tdlib::TdClient;
use tdlib_rs::enums::Update;

// FFI для синхронного вызова TDLib (отключение логов до создания клиента)
#[link(name = "tdjson")]
extern "C" {
    fn td_execute(request: *const c_char) -> *const c_char;
}

/// Отключаем логи TDLib синхронно, до создания клиента
fn disable_tdlib_logs() {
    let request = r#"{"@type":"setLogVerbosityLevel","new_verbosity_level":0}"#;
    let c_request = CString::new(request).unwrap();
    unsafe {
        let _ = td_execute(c_request.as_ptr());
    }

    // Также перенаправляем логи в никуда
    let request2 = r#"{"@type":"setLogStream","log_stream":{"@type":"logStreamEmpty"}}"#;
    let c_request2 = CString::new(request2).unwrap();
    unsafe {
        let _ = td_execute(c_request2.as_ptr());
    }
}

#[derive(PartialEq, Clone)]
enum AppScreen {
    Loading,
    Auth,
    Main,
}

struct App {
    screen: AppScreen,
    td_client: TdClient,
    // Auth state
    phone_input: String,
    code_input: String,
    password_input: String,
    error_message: Option<String>,
    status_message: Option<String>,
    // Main app state
    chats: Vec<ChatInfo>,
    chat_list_state: ListState,
    selected_chat: Option<usize>,
    current_messages: Vec<MessageInfo>,
    folders: Vec<String>,
    selected_folder: usize,
    is_loading: bool,
}

impl App {
    fn new() -> App {
        let mut state = ListState::default();
        state.select(Some(0));

        App {
            screen: AppScreen::Loading,
            td_client: TdClient::new(),
            phone_input: String::new(),
            code_input: String::new(),
            password_input: String::new(),
            error_message: None,
            status_message: Some("Инициализация TDLib...".to_string()),
            chats: Vec::new(),
            chat_list_state: state,
            selected_chat: None,
            current_messages: Vec::new(),
            folders: vec!["All".to_string()],
            selected_folder: 0,
            is_loading: true,
        }
    }

    fn next_chat(&mut self) {
        if self.chats.is_empty() {
            return;
        }
        let i = match self.chat_list_state.selected() {
            Some(i) => {
                if i >= self.chats.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.chat_list_state.select(Some(i));
    }

    fn previous_chat(&mut self) {
        if self.chats.is_empty() {
            return;
        }
        let i = match self.chat_list_state.selected() {
            Some(i) => {
                if i == 0 {
                    self.chats.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.chat_list_state.select(Some(i));
    }

    fn select_current_chat(&mut self) {
        if let Some(i) = self.chat_list_state.selected() {
            if i < self.chats.len() {
                self.selected_chat = Some(i);
            }
        }
    }

    fn close_chat(&mut self) {
        self.selected_chat = None;
        self.current_messages.clear();
    }

    fn select_first_chat(&mut self) {
        if !self.chats.is_empty() {
            self.chat_list_state.select(Some(0));
        }
    }

    fn get_selected_chat_id(&self) -> Option<i64> {
        self.selected_chat
            .and_then(|idx| self.chats.get(idx))
            .map(|chat| chat.id)
    }
}

#[tokio::main]
async fn main() -> Result<(), io::Error> {
    // Загружаем переменные окружения из .env
    let _ = dotenvy::dotenv();

    // Отключаем логи TDLib ДО создания клиента
    disable_tdlib_logs();

    // Запускаем поток для получения updates от TDLib
    let (update_tx, update_rx) = mpsc::channel::<Update>();
    std::thread::spawn(move || {
        loop {
            if let Some((update, _client_id)) = tdlib_rs::receive() {
                if update_tx.send(update).is_err() {
                    break; // Канал закрыт, выходим
                }
            }
        }
    });

    // Setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Create app state
    let mut app = App::new();
    let res = run_app(&mut terminal, &mut app, update_rx).await;

    // Restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("Error: {:?}", err);
    }

    Ok(())
}

async fn run_app<B: ratatui::backend::Backend>(
    terminal: &mut Terminal<B>,
    app: &mut App,
    update_rx: mpsc::Receiver<Update>,
) -> io::Result<()> {
    // Инициализируем TDLib
    if let Err(e) = app.td_client.init().await {
        app.error_message = Some(e);
    }

    loop {
        // Обрабатываем все доступные обновления от TDLib (неблокирующе)
        while let Ok(update) = update_rx.try_recv() {
            app.td_client.handle_update(update);
        }

        // Обновляем состояние экрана на основе auth_state
        update_screen_state(app).await;

        terminal.draw(|f| ui(f, app))?;

        // Используем poll для неблокирующего чтения событий
        if event::poll(Duration::from_millis(100))? {
            if let Event::Key(key) = event::read()? {
                // Global quit command
                if key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
                    return Ok(());
                }

                match app.screen {
                    AppScreen::Loading => {
                        // В состоянии загрузки игнорируем ввод
                    }
                    AppScreen::Auth => handle_auth_input(app, key.code).await,
                    AppScreen::Main => handle_main_input(app, key).await,
                }
            }
        }
    }
}

async fn update_screen_state(app: &mut App) {
    let prev_screen = app.screen.clone();

    match &app.td_client.auth_state {
        AuthState::WaitTdlibParameters => {
            app.screen = AppScreen::Loading;
            app.status_message = Some("Инициализация TDLib...".to_string());
        }
        AuthState::WaitPhoneNumber | AuthState::WaitCode | AuthState::WaitPassword => {
            app.screen = AppScreen::Auth;
            app.is_loading = false;
        }
        AuthState::Ready => {
            if prev_screen != AppScreen::Main {
                app.screen = AppScreen::Main;
                app.is_loading = true;
                app.status_message = Some("Загрузка чатов...".to_string());

                // Запрашиваем загрузку чатов (они придут через updates)
                if let Err(e) = app.td_client.load_chats(50).await {
                    app.error_message = Some(e);
                }
                app.is_loading = false;
                app.status_message = None;
            }

            // Синхронизируем чаты из td_client в app
            if !app.td_client.chats.is_empty() && app.chats.len() != app.td_client.chats.len() {
                app.chats = app.td_client.chats.clone();
                if app.chat_list_state.selected().is_none() && !app.chats.is_empty() {
                    app.chat_list_state.select(Some(0));
                }
            }
        }
        AuthState::Closed => {
            app.status_message = Some("Соединение закрыто".to_string());
        }
        AuthState::Error(e) => {
            app.error_message = Some(e.clone());
        }
    }
}

async fn handle_auth_input(app: &mut App, key_code: KeyCode) {
    match &app.td_client.auth_state {
        AuthState::WaitPhoneNumber => match key_code {
            KeyCode::Char(c) => {
                app.phone_input.push(c);
                app.error_message = None;
            }
            KeyCode::Backspace => {
                app.phone_input.pop();
                app.error_message = None;
            }
            KeyCode::Enter => {
                if !app.phone_input.is_empty() {
                    app.status_message = Some("Отправка номера...".to_string());
                    match app.td_client.send_phone_number(app.phone_input.clone()).await {
                        Ok(_) => {
                            app.error_message = None;
                            app.status_message = None;
                        }
                        Err(e) => {
                            app.error_message = Some(e);
                            app.status_message = None;
                        }
                    }
                }
            }
            _ => {}
        },
        AuthState::WaitCode => match key_code {
            KeyCode::Char(c) if c.is_numeric() => {
                app.code_input.push(c);
                app.error_message = None;
            }
            KeyCode::Backspace => {
                app.code_input.pop();
                app.error_message = None;
            }
            KeyCode::Enter => {
                if !app.code_input.is_empty() {
                    app.status_message = Some("Проверка кода...".to_string());
                    match app.td_client.send_code(app.code_input.clone()).await {
                        Ok(_) => {
                            app.error_message = None;
                            app.status_message = None;
                        }
                        Err(e) => {
                            app.error_message = Some(e);
                            app.status_message = None;
                        }
                    }
                }
            }
            _ => {}
        },
        AuthState::WaitPassword => match key_code {
            KeyCode::Char(c) => {
                app.password_input.push(c);
                app.error_message = None;
            }
            KeyCode::Backspace => {
                app.password_input.pop();
                app.error_message = None;
            }
            KeyCode::Enter => {
                if !app.password_input.is_empty() {
                    app.status_message = Some("Проверка пароля...".to_string());
                    match app.td_client.send_password(app.password_input.clone()).await {
                        Ok(_) => {
                            app.error_message = None;
                            app.status_message = None;
                        }
                        Err(e) => {
                            app.error_message = Some(e);
                            app.status_message = None;
                        }
                    }
                }
            }
            _ => {}
        },
        _ => {}
    }
}

async fn handle_main_input(app: &mut App, key: event::KeyEvent) {
    let has_super = key.modifiers.contains(KeyModifiers::SUPER);
    let has_ctrl = key.modifiers.contains(KeyModifiers::CONTROL);

    match key.code {
        // Navigate down: j, Down, д (Russian)
        KeyCode::Char('j') | KeyCode::Char('д') | KeyCode::Down if !has_super && !has_ctrl => {
            app.next_chat();
        }
        // Navigate up: k, Up, л (Russian)
        KeyCode::Char('k') | KeyCode::Char('л') | KeyCode::Up if !has_super && !has_ctrl => {
            app.previous_chat();
        }
        // Jump to first chat: Cmd+Up or Ctrl+k/л
        KeyCode::Up if has_super => {
            app.select_first_chat();
        }
        KeyCode::Char('k') | KeyCode::Char('л') if has_ctrl => {
            app.select_first_chat();
        }
        KeyCode::Enter => {
            let prev_selected = app.selected_chat;
            app.select_current_chat();

            // Если выбрали новый чат, загружаем историю
            if app.selected_chat != prev_selected {
                if let Some(chat_id) = app.get_selected_chat_id() {
                    app.status_message = Some("Загрузка сообщений...".to_string());
                    match app.td_client.get_chat_history(chat_id, 30).await {
                        Ok(messages) => {
                            app.current_messages = messages;
                            app.status_message = None;
                        }
                        Err(e) => {
                            app.error_message = Some(e);
                            app.status_message = None;
                        }
                    }
                }
            }
        }
        KeyCode::Esc => {
            app.close_chat();
        }
        KeyCode::Char('r') if has_ctrl => {
            // Обновить список чатов
            app.status_message = Some("Обновление чатов...".to_string());
            if let Err(e) = app.td_client.load_chats(50).await {
                app.error_message = Some(e);
            }
            app.status_message = None;
        }
        KeyCode::Char(c) if c >= '1' && c <= '9' => {
            let folder_idx = (c as usize) - ('1' as usize);
            if folder_idx < app.folders.len() {
                app.selected_folder = folder_idx;
            }
        }
        _ => {}
    }
}

fn ui(f: &mut Frame, app: &mut App) {
    match app.screen {
        AppScreen::Loading => render_loading_screen(f, app),
        AppScreen::Auth => render_auth_screen(f, app),
        AppScreen::Main => render_main_screen(f, app),
    }
}

fn render_loading_screen(f: &mut Frame, app: &App) {
    let area = f.area();

    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Percentage(40),
            Constraint::Length(5),
            Constraint::Percentage(40),
        ])
        .split(area);

    let message = app
        .status_message
        .as_deref()
        .unwrap_or("Загрузка...");

    let loading = Paragraph::new(message)
        .style(
            Style::default()
                .fg(Color::Cyan)
                .add_modifier(Modifier::BOLD),
        )
        .alignment(Alignment::Center)
        .block(
            Block::default()
                .borders(Borders::ALL)
                .title(" TTUI "),
        );

    f.render_widget(loading, chunks[1]);
}

fn render_auth_screen(f: &mut Frame, app: &App) {
    let area = f.area();

    let vertical_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Percentage(30),
            Constraint::Length(15),
            Constraint::Percentage(30),
        ])
        .split(area);

    let horizontal_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage(25),
            Constraint::Percentage(50),
            Constraint::Percentage(25),
        ])
        .split(vertical_chunks[1]);

    let auth_area = horizontal_chunks[1];

    let auth_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3), // Title
            Constraint::Length(4), // Instructions
            Constraint::Length(3), // Input
            Constraint::Length(2), // Error/Status message
            Constraint::Min(0),    // Spacer
        ])
        .split(auth_area);

    // Title
    let title = Paragraph::new("TTUI - Telegram Authentication")
        .style(
            Style::default()
                .fg(Color::Cyan)
                .add_modifier(Modifier::BOLD),
        )
        .alignment(Alignment::Center)
        .block(Block::default().borders(Borders::ALL));
    f.render_widget(title, auth_chunks[0]);

    // Instructions and Input based on auth state
    match &app.td_client.auth_state {
        AuthState::WaitPhoneNumber => {
            let instructions = vec![
                Line::from("Введите номер телефона в международном формате"),
                Line::from("Пример: +79991111111"),
            ];
            let instructions_widget = Paragraph::new(instructions)
                .style(Style::default().fg(Color::Gray))
                .alignment(Alignment::Center)
                .block(Block::default().borders(Borders::NONE));
            f.render_widget(instructions_widget, auth_chunks[1]);

            let input_text = format!("📱 {}", app.phone_input);
            let input = Paragraph::new(input_text)
                .style(Style::default().fg(Color::Yellow))
                .alignment(Alignment::Center)
                .block(
                    Block::default()
                        .borders(Borders::ALL)
                        .title(" Phone Number "),
                );
            f.render_widget(input, auth_chunks[2]);
        }
        AuthState::WaitCode => {
            let instructions = vec![
                Line::from("Введите код подтверждения из Telegram"),
                Line::from("Код был отправлен на ваш номер"),
            ];
            let instructions_widget = Paragraph::new(instructions)
                .style(Style::default().fg(Color::Gray))
                .alignment(Alignment::Center)
                .block(Block::default().borders(Borders::NONE));
            f.render_widget(instructions_widget, auth_chunks[1]);

            let input_text = format!("🔐 {}", app.code_input);
            let input = Paragraph::new(input_text)
                .style(Style::default().fg(Color::Yellow))
                .alignment(Alignment::Center)
                .block(
                    Block::default()
                        .borders(Borders::ALL)
                        .title(" Verification Code "),
                );
            f.render_widget(input, auth_chunks[2]);
        }
        AuthState::WaitPassword => {
            let instructions = vec![
                Line::from("Введите пароль двухфакторной аутентификации"),
                Line::from(""),
            ];
            let instructions_widget = Paragraph::new(instructions)
                .style(Style::default().fg(Color::Gray))
                .alignment(Alignment::Center)
                .block(Block::default().borders(Borders::NONE));
            f.render_widget(instructions_widget, auth_chunks[1]);

            let masked_password = "*".repeat(app.password_input.len());
            let input_text = format!("🔒 {}", masked_password);
            let input = Paragraph::new(input_text)
                .style(Style::default().fg(Color::Yellow))
                .alignment(Alignment::Center)
                .block(Block::default().borders(Borders::ALL).title(" Password "));
            f.render_widget(input, auth_chunks[2]);
        }
        _ => {}
    }

    // Error or status message
    if let Some(error) = &app.error_message {
        let error_widget = Paragraph::new(error.as_str())
            .style(Style::default().fg(Color::Red))
            .alignment(Alignment::Center);
        f.render_widget(error_widget, auth_chunks[3]);
    } else if let Some(status) = &app.status_message {
        let status_widget = Paragraph::new(status.as_str())
            .style(Style::default().fg(Color::Yellow))
            .alignment(Alignment::Center);
        f.render_widget(status_widget, auth_chunks[3]);
    }
}

fn render_main_screen(f: &mut Frame, app: &mut App) {
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3), // Folders/tabs
            Constraint::Min(0),    // Main content
            Constraint::Length(1), // Commands footer
        ])
        .split(f.area());

    render_folders(f, chunks[0], app);

    let main_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage(30), // Chat list
            Constraint::Percentage(70), // Messages area
        ])
        .split(chunks[1]);

    render_chat_list(f, main_chunks[0], app);
    render_messages(f, main_chunks[1], app);
    render_footer(f, chunks[2], app);
}

fn render_folders(f: &mut Frame, area: Rect, app: &App) {
    let mut spans = vec![];

    for (i, folder) in app.folders.iter().enumerate() {
        let style = if i == app.selected_folder {
            Style::default()
                .fg(Color::Cyan)
                .add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(Color::White)
        };

        spans.push(Span::styled(format!(" {}:{} ", i + 1, folder), style));
        if i < app.folders.len() - 1 {
            spans.push(Span::raw("│"));
        }
    }

    let folders_line = Line::from(spans);
    let folders_widget = Paragraph::new(folders_line).block(
        Block::default()
            .title(" TTUI ")
            .borders(Borders::ALL),
    );

    f.render_widget(folders_widget, area);
}

fn render_chat_list(f: &mut Frame, area: Rect, app: &mut App) {
    let chat_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3), // Search box
            Constraint::Min(0),    // Chat list
            Constraint::Length(3), // User status
        ])
        .split(area);

    // Search box
    let search = Paragraph::new("🔍 Search...")
        .block(Block::default().borders(Borders::ALL))
        .style(Style::default().fg(Color::DarkGray));
    f.render_widget(search, chat_chunks[0]);

    // Chat list
    let items: Vec<ListItem> = app
        .chats
        .iter()
        .enumerate()
        .map(|(idx, chat)| {
            let is_selected = app.selected_chat == Some(idx);
            let prefix = if is_selected { "▌ " } else { "  " };

            let unread_badge = if chat.unread_count > 0 {
                format!(" ({})", chat.unread_count)
            } else {
                String::new()
            };

            let content = format!("{}{}{}", prefix, chat.title, unread_badge);
            let style = Style::default().fg(Color::White);

            ListItem::new(content).style(style)
        })
        .collect();

    let chats_list = List::new(items)
        .block(Block::default().borders(Borders::ALL))
        .highlight_style(
            Style::default()
                .add_modifier(Modifier::ITALIC)
                .fg(Color::Yellow),
        );

    f.render_stateful_widget(chats_list, chat_chunks[1], &mut app.chat_list_state);

    // User status
    let status = Paragraph::new("[User: Online]")
        .block(Block::default().borders(Borders::ALL))
        .style(Style::default().fg(Color::Green));
    f.render_widget(status, chat_chunks[2]);
}

fn render_messages(f: &mut Frame, area: Rect, app: &App) {
    if let Some(chat_idx) = app.selected_chat {
        if let Some(chat) = app.chats.get(chat_idx) {
            let message_chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints([
                    Constraint::Length(3), // Chat header
                    Constraint::Min(0),    // Messages
                    Constraint::Length(3), // Input box
                ])
                .split(area);

            // Chat header
            let header = Paragraph::new(format!("👤 {}", chat.title))
                .block(Block::default().borders(Borders::ALL))
                .style(
                    Style::default()
                        .fg(Color::Cyan)
                        .add_modifier(Modifier::BOLD),
                );
            f.render_widget(header, message_chunks[0]);

            // Messages
            let mut lines: Vec<Line> = Vec::new();

            for msg in &app.current_messages {
                let sender_style = if msg.is_outgoing {
                    Style::default()
                        .fg(Color::Green)
                        .add_modifier(Modifier::BOLD)
                } else {
                    Style::default()
                        .fg(Color::Cyan)
                        .add_modifier(Modifier::BOLD)
                };

                let sender_name = if msg.is_outgoing {
                    "You".to_string()
                } else {
                    msg.sender_name.clone()
                };

                let read_mark = if msg.is_outgoing {
                    if msg.is_read { " ✓✓" } else { " ✓" }
                } else {
                    ""
                };

                // Форматируем время
                let time = format_timestamp(msg.date);

                lines.push(Line::from(vec![
                    Span::styled(format!("{} ", sender_name), sender_style),
                    Span::raw("── "),
                    Span::styled(format!("{}{}", time, read_mark), Style::default().fg(Color::DarkGray)),
                ]));
                lines.push(Line::from(msg.content.clone()));
                lines.push(Line::from(""));
            }

            if lines.is_empty() {
                lines.push(Line::from(Span::styled(
                    "Нет сообщений",
                    Style::default().fg(Color::DarkGray),
                )));
            }

            let messages_widget =
                Paragraph::new(lines).block(Block::default().borders(Borders::ALL));
            f.render_widget(messages_widget, message_chunks[1]);

            // Input box
            let input = Paragraph::new("> ...")
                .block(Block::default().borders(Borders::ALL))
                .style(Style::default().fg(Color::Yellow));
            f.render_widget(input, message_chunks[2]);
        }
    } else {
        let empty = Paragraph::new("Выберите чат").block(Block::default().borders(Borders::ALL))
            .style(Style::default().fg(Color::DarkGray))
            .alignment(Alignment::Center);
        f.render_widget(empty, area);
    }
}

fn render_footer(f: &mut Frame, area: Rect, app: &App) {
    let status = if let Some(msg) = &app.status_message {
        format!(" {} ", msg)
    } else if let Some(err) = &app.error_message {
        format!(" Error: {} ", err)
    } else {
        " j/k: Navigate | Ctrl+k: First | Enter: Open | Esc: Close | Ctrl+R: Refresh | Ctrl+C: Quit ".to_string()
    };

    let style = if app.error_message.is_some() {
        Style::default().fg(Color::Red)
    } else if app.status_message.is_some() {
        Style::default().fg(Color::Yellow)
    } else {
        Style::default().fg(Color::DarkGray)
    };

    let footer = Paragraph::new(status).style(style);
    f.render_widget(footer, area);
}

fn format_timestamp(timestamp: i32) -> String {
    use std::time::{SystemTime, UNIX_EPOCH};

    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs() as i32;

    let diff = now - timestamp;

    if diff < 60 {
        "just now".to_string()
    } else if diff < 3600 {
        format!("{}m ago", diff / 60)
    } else if diff < 86400 {
        format!("{}h ago", diff / 3600)
    } else {
        // Показываем дату
        let secs = timestamp as u64;
        let days = secs / 86400;
        format!("{}d ago", (now as u64 / 86400) - days)
    }
}
