create type public."Completion Status" as enum ('Complete', 'Demo', 'Alpha', 'Beta');

alter table if exists public.hacks
  add column if not exists is_archive boolean not null default false;

alter table if exists public.hacks
  add column if not exists rejected boolean not null default false;

alter table if exists public.hacks
  add column if not exists rejected_at timestamp with time zone;

alter table if exists public.hacks
  add column if not exists rejected_reason text;

alter table if exists public.hacks
  add column if not exists rejected_by uuid;

alter table if exists public.hacks
  add column if not exists completion_status "Completion Status";

-- Foreign key for rejected_by -> auth.users(id)
alter table "public"."hacks" add constraint "hacks_rejected_by_fkey" FOREIGN KEY (rejected_by) REFERENCES auth.users(id) ON DELETE SET NULL not valid;
alter table "public"."hacks" validate constraint "hacks_rejected_by_fkey";


CREATE OR REPLACE FUNCTION public.is_archive_hack_for_archiver(hack_slug text)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
AS $$
  SELECT EXISTS (
    SELECT 1
    FROM public.hacks h
    WHERE h.slug = hack_slug
      AND h.is_archive = true
  );
$$;


create table if not exists public.patch_groups (
  "id" bigint generated by default as identity not null,
  "created_at" timestamp with time zone not null default now(),
  "updated_at" timestamp with time zone not null default now(),
  "name" text not null,
  "hack_slug" text not null,
  "patch_id" bigint not null,
  "order" integer not null
);

alter table public.patch_groups owner to "postgres";

-- Primary key
CREATE UNIQUE INDEX patch_groups_pkey ON public.patch_groups USING btree (id);
alter table "public"."patch_groups" add constraint "patch_groups_pkey" PRIMARY KEY using index "patch_groups_pkey";

-- Foreign keys
alter table "public"."patch_groups" add constraint "patch_groups_patch_id_fkey" FOREIGN KEY (patch_id) REFERENCES patches(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
alter table "public"."patch_groups" validate constraint "patch_groups_patch_id_fkey";

alter table "public"."patch_groups" add constraint "patch_groups_hack_slug_fkey" FOREIGN KEY (hack_slug) REFERENCES hacks(slug) ON UPDATE CASCADE ON DELETE CASCADE not valid;
alter table "public"."patch_groups" validate constraint "patch_groups_hack_slug_fkey";

-- Unique constraints
-- A patch can only appear once per group
CREATE UNIQUE INDEX patch_groups_hack_slug_name_patch_id_key ON public.patch_groups USING btree (hack_slug, name, patch_id);
alter table "public"."patch_groups" add constraint "patch_groups_hack_slug_name_patch_id_key" UNIQUE using index "patch_groups_hack_slug_name_patch_id_key";

-- Performance indexes
CREATE INDEX patch_groups_hack_slug_idx ON public.patch_groups USING btree (hack_slug);
CREATE INDEX patch_groups_patch_id_idx ON public.patch_groups USING btree (patch_id);
CREATE INDEX patch_groups_name_idx ON public.patch_groups USING btree (name);

-- Enable RLS
alter table "public"."patch_groups" enable row level security;

-- RLS Policies
-- Public read access (assuming patches are public)
create policy "Patch groups are viewable by everyone"
on "public"."patch_groups"
for select
using (true);

-- Allow authenticated users to insert patch groups for their own hacks
create policy "Users can insert patch groups for own hacks"
on "public"."patch_groups"
for insert
with check (
  public.is_admin() OR
  (public.is_archiver() AND public.is_archive_hack_for_archiver(patch_groups.hack_slug)) OR
  EXISTS (
    SELECT 1
    FROM public.hacks h
    WHERE h.slug = patch_groups.hack_slug
    AND h.created_by = auth.uid()
  )
);

-- Allow authenticated users to update patch groups for their own hacks
create policy "Users can update patch groups for own hacks"
on "public"."patch_groups"
for update
using (
  public.is_admin() OR
  (public.is_archiver() AND public.is_archive_hack_for_archiver(patch_groups.hack_slug)) OR
  EXISTS (
    SELECT 1
    FROM public.hacks h
    WHERE h.slug = patch_groups.hack_slug
    AND h.created_by = auth.uid()
  )
)
with check (
  public.is_admin() OR
  (public.is_archiver() AND public.is_archive_hack_for_archiver(patch_groups.hack_slug)) OR
  EXISTS (
    SELECT 1
    FROM public.hacks h
    WHERE h.slug = patch_groups.hack_slug
    AND h.created_by = auth.uid()
  )
);

-- Allow authenticated users to delete patch groups for their own hacks
create policy "Users can delete patch groups for own hacks"
on "public"."patch_groups"
for delete
using (
  public.is_admin() OR
  (public.is_archiver() AND public.is_archive_hack_for_archiver(patch_groups.hack_slug)) OR
  EXISTS (
    SELECT 1
    FROM public.hacks h
    WHERE h.slug = patch_groups.hack_slug
    AND h.created_by = auth.uid()
  )
);

-- Trigger for updated_at
CREATE OR REPLACE TRIGGER set_patch_groups_updated_at
BEFORE UPDATE ON public.patch_groups
FOR EACH ROW
EXECUTE FUNCTION public.set_updated_at();
