-- PostgreSQL / Supabase schema for the exam result query module.
-- Each exam is independent. Scores are stored under one exam only and do
-- not affect any other exam.

create extension if not exists pgcrypto;

create table if not exists public.exam_exams (
    id uuid primary key default gen_random_uuid(),
    exam_code text not null unique,
    exam_name text not null,
    exam_date date,
    is_published boolean not null default true,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now()
);

create table if not exists public.exam_results (
    id uuid primary key default gen_random_uuid(),
    exam_id uuid not null references public.exam_exams(id) on delete cascade,
    student_name text not null,
    admission_no text not null,
    class_name text,
    remark text,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    constraint exam_results_one_candidate_per_exam unique (exam_id, admission_no, student_name)
);

create table if not exists public.exam_score_items (
    id uuid primary key default gen_random_uuid(),
    result_id uuid not null references public.exam_results(id) on delete cascade,
    item_name text not null,
    score numeric(10, 2) not null,
    full_score numeric(10, 2),
    sort_order integer not null default 0,
    created_at timestamptz not null default now()
);

create index if not exists exam_results_lookup_idx
    on public.exam_results (exam_id, student_name, admission_no);

create unique index if not exists exam_score_items_unique_item_idx
    on public.exam_score_items (result_id, item_name);

create index if not exists exam_score_items_result_idx
    on public.exam_score_items (result_id, sort_order);

grant select on public.exam_exams to anon, authenticated;
grant select on public.exam_results to anon, authenticated;
grant select on public.exam_score_items to anon, authenticated;

alter table public.exam_exams enable row level security;
alter table public.exam_results enable row level security;
alter table public.exam_score_items enable row level security;

drop policy if exists "Public can read published exams" on public.exam_exams;
create policy "Public can read published exams"
    on public.exam_exams
    for select
    to anon, authenticated
    using (is_published = true);

drop policy if exists "Public can read published exam results" on public.exam_results;
create policy "Public can read published exam results"
    on public.exam_results
    for select
    to anon, authenticated
    using (
        exists (
            select 1
            from public.exam_exams
            where public.exam_exams.id = exam_results.exam_id
              and public.exam_exams.is_published = true
        )
    );

drop policy if exists "Public can read published score items" on public.exam_score_items;
create policy "Public can read published score items"
    on public.exam_score_items
    for select
    to anon, authenticated
    using (
        exists (
            select 1
            from public.exam_results
            join public.exam_exams on public.exam_exams.id = public.exam_results.exam_id
            where public.exam_results.id = exam_score_items.result_id
              and public.exam_exams.is_published = true
        )
    );

insert into public.exam_exams (exam_code, exam_name, exam_date)
values
    ('2026-spring-midterm', '2026 年春季期中考试', '2026-04-18'),
    ('2026-spring-monthly-01', '2026 年春季第一次月考', '2026-03-12')
on conflict (exam_code) do nothing;

with target_exam as (
    select id from public.exam_exams where exam_code = '2026-spring-midterm'
),
inserted_result as (
    insert into public.exam_results (exam_id, student_name, admission_no, class_name, remark)
    select id, '张三', 'EX20260001', '高一 1 班', '本场考试独立计分，实验规范扣分仅影响本场期中考试。'
    from target_exam
    on conflict (exam_id, admission_no, student_name) do update
        set class_name = excluded.class_name,
            remark = excluded.remark,
            updated_at = now()
    returning id
)
insert into public.exam_score_items (result_id, item_name, score, full_score, sort_order)
select id, item_name, score, full_score, sort_order
from inserted_result,
(values
    ('语文', 108, 150, 10),
    ('数学', 126, 150, 20),
    ('英语', 119, 150, 30),
    ('实验规范扣分', -2, null, 40)
) as item_rows(item_name, score, full_score, sort_order)
on conflict (result_id, item_name) do update
    set score = excluded.score,
        full_score = excluded.full_score,
        sort_order = excluded.sort_order;
