#pragma once

// terminal_panel — emulador TTY embebible en ImGui.
//
// Arranca un proceso hijo via PTY (Linux: forkpty) o ConPTY (Windows) y
// renderiza su output en un child window ImGui con soporte basico de ANSI:
// colores FG/BG 16-color, bold, cursor pos, clear screen/line.
//
// Uso basico:
//   static fn_term::TerminalPanel term;
//   term.shell = "/bin/bash";
//
//   if (!term.is_open()) fn_term::open(term);
//   fn_term::render(term);
//   if (!term.readonly) fn_term::send(term, "ls\n");
//   // Al cerrar:
//   fn_term::close(term);
//
// Thread-safety: open/render/send/close deben llamarse desde el hilo ImGui.
// El reader thread interno es gestionado por la implementacion.
//
// Plataformas:
//   Linux/macOS: terminal_panel_linux.cpp  (forkpty + read no-blocking en thread)
//   Windows:     terminal_panel_windows.cpp (ConPTY CreatePseudoConsole)

#include "core/ansi_parser.h"

#include <atomic>
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

namespace fn_term {

// Una linea del scrollback: vector de celdas ya parseadas.
using TermLine = std::vector<AnsiCell>;

// Configuracion y estado del panel.
struct TerminalPanel {
    // --- Config (set antes de open(), no cambiar en vivo) ---
    std::string shell;            // "" → auto-detect (/bin/bash linux, cmd.exe windows)
    std::string cwd;              // "" → directorio actual del proceso padre
    std::vector<std::string> env; // KEY=VAL adicionales al entorno heredado
    int  scrollback_lines = 5000; // max filas en el ring buffer
    bool readonly = false;        // si true, no reenvía input del teclado

    // --- Estado interno (gestionado por open/close/render) ---
    // No modificar directamente.

    // Proceso hijo
    int  child_pid  = -1;     // Linux: PID del hijo; -1 si no abierto
    int  master_fd  = -1;     // Linux: fd del extremo master del PTY
    void* proc_handle = nullptr; // Windows: HANDLE del proceso hijo (HANDLE)
    void* pty_handle  = nullptr; // Windows: HPCON (ConPTY handle)
    void* pipe_read   = nullptr; // Windows: HANDLE pipe de lectura
    void* pipe_write  = nullptr; // Windows: HANDLE pipe de escritura (→ stdin del hijo)

    // Reader thread
    std::thread      reader_thread;
    std::atomic<bool> reader_running{false};

    // Scrollback buffer (protegido por mutex)
    mutable std::mutex          buf_mutex;
    std::vector<TermLine>       lines;          // buffer circular de lineas
    int                         cur_row = 0;    // fila del cursor dentro de `lines`
    int                         cur_col = 0;    // columna del cursor
    bool                        scroll_to_bottom = true;

    // Parser ANSI (solo lo toca el reader thread)
    AnsiParser                  parser;

    // Flag: proceso hijo terminó
    std::atomic<bool>           process_exited{false};
    int                         exit_code = 0;

    // ctor/dtor
    TerminalPanel();
    ~TerminalPanel();
    TerminalPanel(const TerminalPanel&)            = delete;
    TerminalPanel& operator=(const TerminalPanel&) = delete;

    bool is_open() const { return master_fd >= 0 || pipe_read != nullptr; }
};

// Abre el proceso hijo y arranca el reader thread.
// Llama una sola vez antes del primer render.
// Si falla, loguea via fn_log::log_error y deja is_open() == false.
void open(TerminalPanel& panel);

// Renderiza el terminal en el area disponible de ImGui.
// Debe llamarse dentro de un frame ImGui activo.
// Dibuja toolbar (clear, copy, reset, scroll-lock) + scrollback + input.
void render(TerminalPanel& panel);

// Envía texto al stdin del proceso hijo.
// No-op si !is_open() o readonly.
void send(TerminalPanel& panel, const std::string& text);

// Cierra el proceso hijo, espera al reader thread y libera recursos.
void close(TerminalPanel& panel);

// ---- Internals usados por los backends Linux/Windows ----
// (No llamar directamente desde apps.)

// Procesa un chunk de bytes del PTY y los añade al scrollback.
// Llamado desde el reader thread. Thread-safe via buf_mutex.
void process_output(TerminalPanel& panel, const char* data, size_t n);

} // namespace fn_term
