-- PostgreSQL-oriented schema for Rolemaster critical tables.
-- It is intentionally hybrid: relational axes + raw text + parsed JSON.

create table critical_table (
    id bigint generated always as identity primary key,
    slug text not null unique,
    display_name text not null,
    family text not null check (family in ('standard', 'variant_column', 'grouped_variant')),
    source_pdf text not null,
    source_page integer not null default 1,
    extraction_method text not null check (extraction_method in ('text', 'ocr', 'manual')),
    notes text,
    created_at timestamptz not null default now()
);

create table critical_group (
    id bigint generated always as identity primary key,
    critical_table_id bigint not null references critical_table(id) on delete cascade,
    group_key text not null,
    label text not null,
    sort_order integer not null,
    unique (critical_table_id, group_key)
);

create table critical_column (
    id bigint generated always as identity primary key,
    critical_table_id bigint not null references critical_table(id) on delete cascade,
    column_key text not null,
    label text not null,
    role text not null default 'severity' check (role in ('severity', 'variant', 'other')),
    sort_order integer not null,
    unique (critical_table_id, column_key)
);

create table critical_roll_band (
    id bigint generated always as identity primary key,
    critical_table_id bigint not null references critical_table(id) on delete cascade,
    label text not null,
    min_roll integer not null,
    max_roll integer,
    sort_order integer not null,
    check (max_roll is null or max_roll >= min_roll),
    unique (critical_table_id, label)
);

create index critical_roll_band_lookup_idx
    on critical_roll_band (critical_table_id, min_roll, max_roll);

create table critical_result (
    id bigint generated always as identity primary key,
    critical_table_id bigint not null references critical_table(id) on delete cascade,
    critical_group_id bigint references critical_group(id) on delete cascade,
    critical_column_id bigint not null references critical_column(id) on delete cascade,
    critical_roll_band_id bigint not null references critical_roll_band(id) on delete cascade,
    is_curated boolean not null default false,
    raw_cell_text text not null,
    description_text text,
    raw_affix_text text,
    parsed_json jsonb not null default '{}'::jsonb,
    parse_status text not null default 'raw' check (parse_status in ('raw', 'partial', 'parsed', 'verified')),
    source_page_number integer,
    source_image_path text,
    source_image_crop jsonb,
    created_at timestamptz not null default now()
);

create unique index critical_result_lookup_uidx
    on critical_result (
        critical_table_id,
        coalesce(critical_group_id, 0),
        critical_column_id,
        critical_roll_band_id
    );

create table critical_branch (
    id bigint generated always as identity primary key,
    critical_result_id bigint not null references critical_result(id) on delete cascade,
    branch_kind text not null default 'conditional' check (branch_kind in ('conditional', 'note', 'override')),
    condition_key text,
    condition_text text not null,
    condition_json jsonb not null default '{}'::jsonb,
    raw_text text not null,
    description_text text,
    raw_affix_text text,
    parsed_json jsonb not null default '{}'::jsonb,
    sort_order integer not null default 1
);

create table critical_effect (
    id bigint generated always as identity primary key,
    critical_result_id bigint references critical_result(id) on delete cascade,
    critical_branch_id bigint references critical_branch(id) on delete cascade,
    effect_code text not null,
    target text,
    value_integer integer,
    value_decimal numeric(10, 2),
    value_expression text,
    duration_rounds integer,
    per_round integer,
    modifier integer,
    body_part text,
    is_permanent boolean not null default false,
    source_type text not null default 'symbol' check (source_type in ('symbol', 'prose', 'manual')),
    source_text text,
    check ((critical_result_id is not null) <> (critical_branch_id is not null))
);

create index critical_effect_lookup_idx
    on critical_effect (effect_code, target);

create index critical_effect_result_idx
    on critical_effect (critical_result_id);

create index critical_effect_branch_idx
    on critical_effect (critical_branch_id);

create index critical_result_parsed_json_gin
    on critical_result using gin (parsed_json);

create index critical_branch_parsed_json_gin
    on critical_branch using gin (parsed_json);

-- Example lookup pattern:
--
-- select
--     t.slug as critical_type,
--     t.display_name as table_name,
--     g.group_key,
--     c.column_key,
--     rb.label as roll_band,
--     rb.min_roll,
--     rb.max_roll,
--     r.description_text,
--     r.raw_affix_text,
--     r.raw_cell_text,
--     r.parsed_json
-- from critical_result r
-- join critical_table t on t.id = r.critical_table_id
-- left join critical_group g on g.id = r.critical_group_id
-- join critical_column c on c.id = r.critical_column_id
-- join critical_roll_band rb on rb.id = r.critical_roll_band_id
-- where t.slug = 'slash'
--   and c.column_key = 'C'
--   and 38 >= rb.min_roll
--   and (rb.max_roll is null or 38 <= rb.max_roll);
