#ifndef HUSH_DOCUMENT_H
#define HUSH_DOCUMENT_H

#include "strbuf.h"

typedef enum {
    BLOCK_PARAGRAPH,
    BLOCK_H1,
    BLOCK_H2,
    BLOCK_H3,
    BLOCK_H4,
    BLOCK_H5,
    BLOCK_H6,
    BLOCK_BULLET,
    BLOCK_NUMBERED,
    BLOCK_QUOTE,
    BLOCK_CODE,
    BLOCK_HR,             /* horizontal rule; text/lang are always empty, never edited */
    BLOCK_TASK_UNCHECKED, /* "- [ ] text" */
    BLOCK_TASK_CHECKED,   /* "- [x] text" */
    BLOCK_IMAGE,          /* "![alt](url)"; text holds the url, alt holds the alt text */
    BLOCK_TABLE_HEADER_CELL, /* one cell of a table's header row; text holds the cell's content */
    BLOCK_TABLE_CELL,        /* one cell of a table's body row; text holds the cell's content */
} BlockType;

typedef struct {
    BlockType type;
    StrBuf text; /* raw text, without block-level prefix. Code blocks may embed '\n'. */
    StrBuf lang; /* BLOCK_CODE only: the fenced code's info-string (e.g. "c"), or empty. */
    StrBuf alt;  /* BLOCK_IMAGE only: the image's alt text, or empty. */
    /* BLOCK_TABLE_HEADER_CELL/BLOCK_TABLE_CELL only. A table is a contiguous run of these blocks
       (like a bulleted list is a run of BLOCK_BULLET blocks) -- these fields let a cell know its
       position without needing a separate table-container block or lookahead. tableCol resetting
       to 0 marks a new row; tableCol == tableCols-1 marks the last cell of a row. */
    int tableCol;    /* 0-indexed column within this cell's row */
    int tableCols;   /* total columns in this cell's table */
    char tableAlign; /* 'l' (default), 'c', or 'r', from the delimiter row */
} Block;

typedef struct {
    Block *blocks;
    int count;
    int cap;
} Document;

/* True for block types that "continue" themselves on Enter (list-like blocks). */
static inline int block_type_is_continuable(BlockType t) {
    return t == BLOCK_BULLET || t == BLOCK_NUMBERED || t == BLOCK_QUOTE
        || t == BLOCK_TASK_UNCHECKED || t == BLOCK_TASK_CHECKED;
}

/* True for a table cell (header or body) -- Enter/Backspace/Delete/vertical-nav/Turn-Into all
   need to treat these specially rather than falling into their generic per-block-type paths. */
static inline int block_type_is_table_cell(BlockType t) {
    return t == BLOCK_TABLE_HEADER_CELL || t == BLOCK_TABLE_CELL;
}

void document_init(Document *doc);
void document_free(Document *doc);

/* Deep-copies `src` into `dst`. `dst` must not already hold live blocks (it is treated as
   uninitialized, not freed first) — used to snapshot state for undo/redo. */
void document_clone(Document *dst, const Document *src);

/* Inserts a new block at `index`, shifting later blocks right. Text is copied. */
void document_insert_block(Document *doc, int index, BlockType type, const char *text, int len);
void document_remove_block(Document *doc, int index);

static inline Block *document_block(Document *doc, int index) {
    return &doc->blocks[index];
}

#endif
