create schema if not exists kbx;

create table if not exists kbx.import_sessions (
    id uuid primary key,
    tenant_id varchar(100) not null,
    user_id varchar(200) not null,
    screen_id varchar(100) not null,
    import_type varchar(150) not null,
    original_file_name varchar(300) not null,
    status varchar(40) not null,
    source_columns jsonb not null default '[]'::jsonb,
    mapping jsonb not null default '[]'::jsonb,
    total_rows integer not null default 0 check (total_rows >= 0),
    valid_rows integer not null default 0 check (valid_rows >= 0),
    invalid_rows integer not null default 0 check (invalid_rows >= 0),
    warning_rows integer not null default 0 check (warning_rows >= 0),
    created_rows integer not null default 0 check (created_rows >= 0),
    updated_rows integer not null default 0 check (updated_rows >= 0),
    progress_percent integer not null default 0 check (progress_percent between 0 and 100),
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    completed_at timestamptz,
    expires_at timestamptz not null default (now() + interval '14 days'),
    failure_code varchar(120),
    failure_message text
);

create index if not exists ix_import_sessions_owner
    on kbx.import_sessions(tenant_id, user_id, created_at desc);
create index if not exists ix_import_sessions_status
    on kbx.import_sessions(status, updated_at);
create index if not exists ix_import_sessions_expiry
    on kbx.import_sessions(expires_at);

-- File bytes are separated from session metadata so normal session queries never load XLSX blobs.
-- This PostgreSQL-backed starter avoids a distributed filesystem dependency. The interface can
-- later be replaced with object storage without changing the import workflow.
create table if not exists kbx.import_files (
    session_id uuid primary key references kbx.import_sessions(id) on delete cascade,
    content_type varchar(150) not null,
    file_size bigint not null check (file_size >= 0),
    sha256 varchar(64) not null,
    data bytea not null
);

create table if not exists kbx.import_rows (
    session_id uuid not null references kbx.import_sessions(id) on delete cascade,
    row_number integer not null check (row_number >= 2),
    raw_data jsonb not null,
    normalized_data jsonb,
    status varchar(30) not null default 'PENDING',
    errors jsonb not null default '[]'::jsonb,
    warnings jsonb not null default '[]'::jsonb,
    domain_key varchar(300),
    primary key(session_id, row_number)
);

create index if not exists ix_import_rows_status
    on kbx.import_rows(session_id, status, row_number);
create index if not exists ix_import_rows_domain_key
    on kbx.import_rows(session_id, domain_key)
    where domain_key is not null;

create table if not exists kbx.saved_import_mappings (
    id uuid primary key,
    tenant_id varchar(100) not null,
    user_id varchar(200) not null,
    import_type varchar(150) not null,
    name varchar(200) not null,
    source_signature varchar(64) not null,
    mapping jsonb not null,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    unique(tenant_id, user_id, import_type, name)
);

create index if not exists ix_saved_import_mapping_signature
    on kbx.saved_import_mappings(tenant_id, user_id, import_type, source_signature);

create table if not exists kbx.import_job_receipts (
    session_id uuid not null references kbx.import_sessions(id) on delete cascade,
    operation varchar(40) not null,
    job_id varchar(100) not null,
    requested_at timestamptz not null default now(),
    primary key(session_id, operation)
);
