gosuto 0.11.1

Gōsuto (ゴースト) — a cyberpunk terminal Matrix client with vim motions
use ratatui::Frame;
use ratatui::style::Style;

use crate::state::{HISTORY_VISIBILITY_OPTIONS, RoomInfoState};
use crate::ui::icons::Icons;
use crate::ui::{form_field, popup, theme};

const POPUP_WIDTH: u16 = 54;
const POPUP_HEIGHT: u16 = 20;

pub fn render(
    state: &RoomInfoState,
    icons: &Icons,
    frame: &mut Frame,
    phase: f32,
    cursor_visible: bool,
) {
    let area = frame.area();
    if area.width < 30 || area.height < 12 {
        return;
    }

    let popup_w = POPUP_WIDTH.min(area.width.saturating_sub(4));
    let popup_h = POPUP_HEIGHT.min(area.height.saturating_sub(4));
    let popup_area = popup::centered_rect(popup_w, popup_h, area);
    let buf = frame.buffer_mut();
    let bounds = *buf.area();

    popup::render_popup_chrome(buf, &bounds, popup_area, "ROOM EDIT", phase);

    let left = popup_area.x + 3;
    let right = popup_area.x + popup_area.width.saturating_sub(3);
    let inner_w = (right - left) as usize;

    if state.loading {
        let msg = "Loading...";
        let mx = left + (inner_w.saturating_sub(msg.len())) as u16 / 2;
        let my = popup_area.y + popup_area.height / 2;
        popup::write_str(buf, &bounds, mx, my, msg, theme::loading_style());
        return;
    }

    let label_s = Style::default().fg(theme::DIM).bg(theme::BG);
    let value_s = Style::default().fg(theme::TEXT).bg(theme::BG);
    let label_x = left + 2;
    let value_x = left + 15;

    let mut row = popup_area.y + 2;

    // Room ID (read-only)
    popup::write_str(buf, &bounds, label_x, row, "ROOM ID", label_s);
    let id_display = popup::truncate_str(&state.room_id, (right - value_x) as usize);
    popup::write_str(buf, &bounds, value_x, row, &id_display, value_s);
    row += 1;

    row += 1;

    // ── Field 0: NAME (editable) ──
    let name_selected = state.selected_field == 0;
    form_field::render_label(buf, left, label_x, row, "NAME", name_selected, icons);

    if state.editing_name {
        form_field::render_editing(buf, value_x, right, row, &state.name_buffer, cursor_visible);
    } else {
        let name = state.name.as_deref().unwrap_or("\u{2014}");
        form_field::render_value(buf, value_x, right, row, name, name_selected);
    }
    row += 1;

    // ── Field 1: TOPIC (editable) ──
    let topic_selected = state.selected_field == 1;
    form_field::render_label(buf, left, label_x, row, "TOPIC", topic_selected, icons);

    if state.editing_topic {
        form_field::render_editing(
            buf,
            value_x,
            right,
            row,
            &state.topic_buffer,
            cursor_visible,
        );
    } else {
        let topic = state.topic.as_deref().unwrap_or("\u{2014}");
        form_field::render_value(buf, value_x, right, row, topic, topic_selected);
    }
    row += 1;

    // ── Field 2: HISTORY (cycle selector) ──
    let hist_selected = state.selected_field == 2;
    form_field::render_label(buf, left, label_x, row, "HISTORY", hist_selected, icons);
    form_field::render_cycle_selector(
        buf,
        value_x,
        row,
        &state.history_visibility,
        hist_selected,
        icons,
    );
    row += 1;

    // History visibility description
    let desc = popup::history_visibility_description(&state.history_visibility);
    let desc_s = Style::default().fg(theme::DIM).bg(theme::BG);
    popup::write_str(buf, &bounds, value_x, row, desc, desc_s);
    row += 1;

    // ── Field 3: ENCRYPTED (editable when unencrypted, read-only when encrypted) ──
    if state.encrypted {
        popup::write_str(buf, &bounds, label_x, row, "ENCRYPTED", label_s);
        popup::write_str(
            buf,
            &bounds,
            value_x,
            row,
            "yes",
            Style::default().fg(theme::GREEN).bg(theme::BG),
        );
    } else {
        let enc_selected = state.selected_field == 3;
        form_field::render_label(buf, left, label_x, row, "ENCRYPTED", enc_selected, icons);
        form_field::render_cycle_selector(
            buf,
            value_x,
            row,
            &state.encryption_selection,
            enc_selected,
            icons,
        );
    }

    // Show saving indicator
    if state.saving {
        row += 2;
        let msg = "saving...";
        let sx = left + (inner_w.saturating_sub(msg.len())) as u16 / 2;
        popup::write_str(buf, &bounds, sx, row, msg, theme::saving_style());
    }

    // Show valid options hint
    row = popup_area.y + popup_area.height.saturating_sub(4);
    let opts: String = if state.selected_field == 3 && !state.encrypted {
        "no | yes".to_string()
    } else {
        HISTORY_VISIBILITY_OPTIONS.join(" | ")
    };
    let opts_x = left + (inner_w.saturating_sub(opts.len())) as u16 / 2;
    popup::write_str(
        buf,
        &bounds,
        opts_x,
        row,
        &opts,
        Style::default().fg(theme::MUTED).bg(theme::BG),
    );

    // Hints
    popup::render_hint(
        buf,
        &bounds,
        popup_area,
        "j/k navigate  Enter edit  Esc close",
    );
}