use crate::command::chat::app::ChatApp;
use crate::tui::components::{ItemList, selectable_row};
use ratatui::{
style::{Modifier, Style},
text::{Line, Span},
};
fn format_timestamp(ts: u64) -> String {
use std::time::{Duration, SystemTime, UNIX_EPOCH};
let dt = UNIX_EPOCH + Duration::from_secs(ts);
let now = SystemTime::now();
let elapsed = now.duration_since(dt).unwrap_or_default();
if elapsed.as_secs() < 60 {
"\u{521a}\u{521a}".to_string()
} else if elapsed.as_secs() < 3600 {
format!("{}\u{5206}\u{949f}\u{524d}", elapsed.as_secs() / 60)
} else if elapsed.as_secs() < 86400 {
format!("{}\u{5c0f}\u{65f6}\u{524d}", elapsed.as_secs() / 3600)
} else if elapsed.as_secs() < 86400 * 30 {
format!("{}\u{5929}\u{524d}", elapsed.as_secs() / 86400)
} else {
let secs = ts;
let days = secs / 86400;
let (y, m, d) = days_to_ymd(days);
format!("{y:04}-{m:02}-{d:02}")
}
}
fn days_to_ymd(days: u64) -> (u64, u64, u64) {
let mut y = 1970;
let mut remaining = days;
loop {
let days_in_year = if is_leap(y) { 366 } else { 365 };
if remaining < days_in_year {
break;
}
remaining -= days_in_year;
y += 1;
}
let month_days = if is_leap(y) {
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
} else {
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
};
let mut m = 1;
for &md in &month_days {
if remaining < md {
break;
}
remaining -= md;
m += 1;
}
(y, m, remaining + 1)
}
fn is_leap(y: u64) -> bool {
y.is_multiple_of(4) && (!y.is_multiple_of(100) || y.is_multiple_of(400))
}
pub(super) fn draw_tab_session_header<'a>(lines: &mut Vec<Line<'a>>, app: &ChatApp) {
let t = &app.ui.theme;
let msg_count = app.state.session.messages.len();
lines.push(Line::from(vec![
Span::styled(
" \u{5f53}\u{524d}\u{4f1a}\u{8bdd}: ",
Style::default().fg(t.config_label),
),
Span::styled(
format!(
"{} ({} \u{6761}\u{6d88}\u{606f})",
&app.session_id, msg_count
),
Style::default()
.fg(t.config_toggle_on)
.add_modifier(Modifier::BOLD),
),
]));
lines.push(Line::from(""));
if app.ui.session_restore_confirm {
lines.push(Line::from(Span::styled(
" \u{26a0}\u{fe0f} \u{5f53}\u{524d}\u{4f1a}\u{8bdd}\u{6709}\u{6d88}\u{606f}\u{ff0c}\u{6062}\u{590d}\u{5c06}\u{5207}\u{6362}\u{5230}\u{5386}\u{53f2}\u{4f1a}\u{8bdd}\u{ff08}\u{5f53}\u{524d}\u{4f1a}\u{8bdd}\u{5df2}\u{81ea}\u{52a8}\u{4fdd}\u{5b58}\u{ff09}",
Style::default()
.fg(t.config_toggle_off)
.add_modifier(Modifier::BOLD),
)));
lines.push(Line::from(Span::styled(
" \u{6309} y/Enter \u{786e}\u{8ba4}\u{6062}\u{590d}\u{ff0c}Esc \u{53d6}\u{6d88}",
Style::default().fg(t.config_dim),
)));
lines.push(Line::from(""));
}
if app.ui.session_list.is_empty() {
lines.push(Line::from(Span::styled(
" (\u{6ca1}\u{6709}\u{5386}\u{53f2}\u{4f1a}\u{8bdd})",
Style::default().fg(t.config_dim),
)));
} else {
lines.push(Line::from(Span::styled(
format!(
" \u{5386}\u{53f2}\u{4f1a}\u{8bdd} ({})",
app.ui.session_list.len()
),
Style::default()
.fg(t.config_label)
.add_modifier(Modifier::BOLD),
)));
lines.push(Line::from(""));
}
}
pub(super) fn draw_tab_session_list<'a>(app: &ChatApp) -> ItemList<'a> {
let t = &app.ui.theme;
let mut list = ItemList::new(t.bg_primary);
for (i, session) in app.ui.session_list.iter().enumerate() {
let is_selected = i == app.ui.session_list_index;
let preview = session
.title
.as_deref()
.or(session.first_message_preview.as_deref())
.unwrap_or("(\u{7a7a}\u{4f1a}\u{8bdd})");
let preview_truncated: String = preview.chars().take(40).collect();
let time_str = format_timestamp(session.updated_at);
let secondary = format!("({} \u{6761}, {})", session.message_count, time_str);
list.push(selectable_row(
&preview_truncated,
&secondary,
is_selected,
t,
));
}
list
}