create table if not exists public.page_refs (
    id uuid primary key default gen_random_uuid(),
    workspace_id uuid not null references public.workspaces(id) on delete cascade,
    source_page_id uuid not null references public.documents(id) on delete cascade,
    source_block_id text,
    target_page_id uuid not null references public.documents(id) on delete cascade,
    alias text,
    display_mode text not null default 'inline' check (display_mode in ('inline','embed')),
    is_previewable boolean not null default true,
    created_by uuid not null references public.profiles(id) on delete cascade,
    created_at timestamptz not null default timezone('utc', now()),
    updated_at timestamptz not null default timezone('utc', now())
);

create index if not exists page_refs_target_idx on public.page_refs (workspace_id, target_page_id, display_mode);
create index if not exists page_refs_source_idx on public.page_refs (workspace_id, source_page_id);
create index if not exists page_refs_recent_idx on public.page_refs (workspace_id, updated_at desc);

create unique index if not exists page_refs_unique_block_ref
    on public.page_refs (workspace_id, source_page_id, coalesce(source_block_id, ''), target_page_id, display_mode);

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

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

alter table public.page_refs enable row level security;

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

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

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

create or replace function public.record_page_ref(
    p_workspace_id uuid,
    p_source_page_id uuid,
    p_source_block_id text,
    p_target_page_id uuid,
    p_alias text,
    p_display_mode text default 'inline',
    p_is_previewable boolean default true,
    p_created_by uuid default auth.uid()
)
returns public.page_refs
language plpgsql
security definer
set search_path = public
as $$
declare
    v_existing public.page_refs%rowtype;
    v_mode text := coalesce(nullif(p_display_mode, ''), 'inline');
begin
    select *
    into v_existing
    from public.page_refs
    where workspace_id = p_workspace_id
      and source_page_id = p_source_page_id
      and target_page_id = p_target_page_id
      and coalesce(source_block_id, '') = coalesce(p_source_block_id, '')
      and display_mode = v_mode
    limit 1;

    if found then
        update public.page_refs
        set alias = coalesce(p_alias, public.page_refs.alias),
            is_previewable = coalesce(p_is_previewable, public.page_refs.is_previewable),
            updated_at = timezone('utc', now())
        where id = v_existing.id
        returning * into v_existing;

        return v_existing;
    end if;

    insert into public.page_refs (
        workspace_id,
        source_page_id,
        source_block_id,
        target_page_id,
        alias,
        display_mode,
        is_previewable,
        created_by
    )
    values (
        p_workspace_id,
        p_source_page_id,
        p_source_block_id,
        p_target_page_id,
        p_alias,
        v_mode,
        coalesce(p_is_previewable, true),
        coalesce(p_created_by, auth.uid())
    )
    returning * into v_existing;

    return v_existing;
end;
$$;

create or replace function public.list_backlinks(
    p_workspace_id uuid,
    p_target_page_id uuid,
    p_limit integer default 50,
    p_offset integer default 0
)
returns table (
    id uuid,
    source_page_id uuid,
    source_block_id text,
    alias text,
    display_mode text,
    is_previewable boolean,
    created_at timestamptz,
    updated_at timestamptz,
    source_title text,
    workspace_id uuid
)
language sql
security definer
set search_path = public
as $$
    select
        r.id,
        r.source_page_id,
        r.source_block_id,
        r.alias,
        r.display_mode,
        r.is_previewable,
        r.created_at,
        r.updated_at,
        d.title as source_title,
        r.workspace_id
    from public.page_refs r
    join public.documents d on d.id = r.source_page_id
    where r.workspace_id = p_workspace_id
      and r.target_page_id = p_target_page_id
      and d.workspace_id = p_workspace_id
    order by r.updated_at desc
    limit greatest(p_limit, 1)
    offset greatest(p_offset, 0);
$$;
