create table if not exists public.document_tables (
    id uuid primary key default gen_random_uuid(),
    workspace_id uuid not null references public.workspaces(id) on delete cascade,
    document_id uuid not null references public.documents(id) on delete cascade,
    title text not null default '未命名表格',
    schema jsonb not null default '{}'::jsonb,
    view_preferences jsonb not null default '{}'::jsonb,
    is_archived boolean not null default false,
    snapshot jsonb,
    last_synced_at timestamptz,
    created_by uuid references public.profiles(id) on delete set null,
    updated_by uuid references public.profiles(id) on delete set null,
    created_at timestamptz not null default timezone('utc', now()),
    updated_at timestamptz not null default timezone('utc', now())
);

create index if not exists document_tables_workspace_idx
    on public.document_tables (workspace_id, updated_at desc);

create index if not exists document_tables_document_idx
    on public.document_tables (document_id, updated_at desc);

create index if not exists document_tables_archived_idx
    on public.document_tables (workspace_id, is_archived, updated_at desc);

create or replace function public.set_document_tables_updated_at()
returns trigger
language plpgsql
security invoker
as $$
begin
    new.updated_at := timezone('utc', now());
    return new;
end;
$$;

drop trigger if exists set_document_tables_updated_at on public.document_tables;
create trigger set_document_tables_updated_at
before update on public.document_tables
for each row
execute procedure public.set_document_tables_updated_at();

create or replace function public.ensure_document_table_workspace()
returns trigger
language plpgsql
security invoker
as $$
declare
    v_workspace uuid;
begin
    select workspace_id
    into v_workspace
    from public.documents
    where id = new.document_id;

    if not found then
        raise exception 'Document % not found when creating document table', new.document_id;
    end if;

    if new.workspace_id is null then
        new.workspace_id := v_workspace;
    elsif new.workspace_id <> v_workspace then
        raise exception 'Workspace mismatch between document table and document %', new.document_id;
    end if;

    return new;
end;
$$;

drop trigger if exists ensure_document_table_workspace on public.document_tables;
create trigger ensure_document_table_workspace
before insert or update on public.document_tables
for each row
execute procedure public.ensure_document_table_workspace();

alter table public.document_tables enable row level security;

drop policy if exists "Select tables within workspace" on public.document_tables;
create policy "Select tables within workspace"
    on public.document_tables
    for select
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_tables.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Insert tables within workspace" on public.document_tables;
create policy "Insert tables within workspace"
    on public.document_tables
    for insert
    with check (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_tables.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Update tables within workspace" on public.document_tables;
create policy "Update tables within workspace"
    on public.document_tables
    for update
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_tables.workspace_id
              and wm.user_id = auth.uid()
        )
    )
    with check (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_tables.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Delete tables within workspace" on public.document_tables;
create policy "Delete tables within workspace"
    on public.document_tables
    for delete
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_tables.workspace_id
              and wm.user_id = auth.uid()
        )
    );

create table if not exists public.document_table_rows (
    id uuid primary key default gen_random_uuid(),
    workspace_id uuid not null references public.workspaces(id) on delete cascade,
    document_id uuid not null references public.documents(id) on delete cascade,
    table_id uuid not null references public.document_tables(id) on delete cascade,
    row_index integer not null,
    row_data jsonb not null default '{}'::jsonb,
    row_hash text,
    is_deleted boolean not null default false,
    updated_by uuid references public.profiles(id) on delete set null,
    created_at timestamptz not null default timezone('utc', now()),
    updated_at timestamptz not null default timezone('utc', now())
);

create unique index if not exists document_table_rows_unique_row
    on public.document_table_rows (table_id, row_index)
    where is_deleted = false;

create index if not exists document_table_rows_workspace_idx
    on public.document_table_rows (workspace_id, updated_at desc);

create index if not exists document_table_rows_table_idx
    on public.document_table_rows (table_id, row_index);

create or replace function public.set_document_table_rows_updated_at()
returns trigger
language plpgsql
security invoker
as $$
begin
    new.updated_at := timezone('utc', now());
    return new;
end;
$$;

drop trigger if exists set_document_table_rows_updated_at on public.document_table_rows;
create trigger set_document_table_rows_updated_at
before update on public.document_table_rows
for each row
execute procedure public.set_document_table_rows_updated_at();

create or replace function public.sync_document_table_row_meta()
returns trigger
language plpgsql
security invoker
as $$
declare
    v_table record;
begin
    select workspace_id, document_id
    into v_table
    from public.document_tables
    where id = new.table_id;

    if not found then
        raise exception 'Document table % not found when creating row', new.table_id;
    end if;

    new.workspace_id := v_table.workspace_id;
    new.document_id := v_table.document_id;

    return new;
end;
$$;

drop trigger if exists sync_document_table_row_meta on public.document_table_rows;
create trigger sync_document_table_row_meta
before insert or update on public.document_table_rows
for each row
execute procedure public.sync_document_table_row_meta();

alter table public.document_table_rows enable row level security;

drop policy if exists "Select table rows within workspace" on public.document_table_rows;
create policy "Select table rows within workspace"
    on public.document_table_rows
    for select
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_table_rows.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Insert table rows within workspace" on public.document_table_rows;
create policy "Insert table rows within workspace"
    on public.document_table_rows
    for insert
    with check (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_table_rows.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Update table rows within workspace" on public.document_table_rows;
create policy "Update table rows within workspace"
    on public.document_table_rows
    for update
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_table_rows.workspace_id
              and wm.user_id = auth.uid()
        )
    )
    with check (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_table_rows.workspace_id
              and wm.user_id = auth.uid()
        )
    );

drop policy if exists "Delete table rows within workspace" on public.document_table_rows;
create policy "Delete table rows within workspace"
    on public.document_table_rows
    for delete
    using (
        exists (
            select 1
            from public.workspace_members wm
            where wm.workspace_id = document_table_rows.workspace_id
              and wm.user_id = auth.uid()
        )
    );
