create table if not exists public.products (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  legacy_id text,
  title text not null,
  price_label text,
  link text,
  type text,
  tags jsonb not null default '[]'::jsonb,
  cover text,
  preview_iframe text,
  detail_images jsonb not null default '[]'::jsonb,
  sort_order integer not null default 0,
  status text not null default 'active' check (status in ('active', 'inactive', 'archived')),
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.timelines (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  school_id uuid references public.schools(id) on delete set null,
  legacy_id text,
  type text,
  title text not null,
  description text,
  event_date date,
  link text,
  sort_order integer not null default 0,
  is_active boolean not null default true,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.video_explanations (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  legacy_id text,
  title text not null,
  description text,
  video_url text,
  thumbnail_url text,
  duration_seconds integer,
  knowledge_tags jsonb not null default '[]'::jsonb,
  is_general boolean not null default false,
  subject_id uuid references public.subjects(id) on delete set null,
  legacy_subject_id text,
  difficulty integer,
  sort_order integer not null default 0,
  is_active boolean not null default true,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.question_videos (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  question_id uuid references public.questions(id) on delete cascade,
  video_id uuid references public.video_explanations(id) on delete cascade,
  legacy_id text,
  legacy_question_id text,
  legacy_video_id text,
  video_type text not null default 'specific',
  sort_order integer not null default 0,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.scoreline_schools (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  legacy_id text,
  name text not null,
  short_name text,
  type text,
  is_hot boolean not null default false,
  sort_order integer not null default 0,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.scoreline_majors (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  school_id uuid references public.scoreline_schools(id) on delete cascade,
  legacy_id text,
  name text not null,
  sort_order integer not null default 0,
  has_restriction boolean not null default false,
  restriction_desc text,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.scoreline_fields (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  legacy_id text,
  field_key text not null,
  field_name text not null,
  field_type text,
  unit text,
  is_filter boolean not null default false,
  is_required boolean not null default false,
  is_visible boolean not null default true,
  is_trend boolean not null default false,
  options jsonb not null default '[]'::jsonb,
  placeholder text,
  description text,
  sort_order integer not null default 0,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id),
  unique (tenant_id, region_id, field_key)
);

create table if not exists public.scoreline_records (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  region_id uuid references public.regions(id) on delete set null,
  school_id uuid references public.scoreline_schools(id) on delete set null,
  major_id uuid references public.scoreline_majors(id) on delete set null,
  legacy_id text,
  year integer not null,
  school_name text,
  major_name text,
  field_values jsonb not null default '{}'::jsonb,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.referral_tracks (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  legacy_id text,
  event_type text not null,
  ref_code text,
  ref_user_id uuid references public.platform_users(id) on delete set null,
  target_user_id uuid references public.platform_users(id) on delete set null,
  source text,
  ip_address text,
  user_agent text,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.badges (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  legacy_id text,
  name text not null,
  description text,
  category text,
  icon_url text,
  level integer,
  unlock_type text,
  condition_field text,
  condition_operator text,
  condition_value numeric,
  condition_extra jsonb not null default '{}'::jsonb,
  sort_order integer not null default 0,
  is_active boolean not null default true,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.user_badges (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  user_id uuid references public.platform_users(id) on delete cascade,
  badge_id uuid references public.badges(id) on delete cascade,
  granted_by uuid references public.platform_users(id) on delete set null,
  legacy_id text,
  note text,
  granted_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.crm_webhook_queue (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  legacy_id text,
  record_id text,
  status text not null default 'pending',
  scheduled_at timestamptz,
  attempts integer not null default 0,
  next_attempt_at timestamptz,
  last_error text,
  last_http_code integer,
  lead_id text,
  sent_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create table if not exists public.crm_webhook_log (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  legacy_id text,
  record_id text,
  http_code integer,
  outcome text,
  error_message text,
  lead_id text,
  request_body text,
  response_summary text,
  signed_at timestamptz,
  attempt integer,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (tenant_id, legacy_id)
);

create index if not exists idx_products_tenant_region on public.products(tenant_id, region_id, sort_order);
create index if not exists idx_timelines_tenant_region on public.timelines(tenant_id, region_id, event_date);
create index if not exists idx_video_explanations_tenant_subject on public.video_explanations(tenant_id, subject_id);
create index if not exists idx_scoreline_records_tenant_year on public.scoreline_records(tenant_id, region_id, year desc);
create index if not exists idx_referral_tracks_tenant_event on public.referral_tracks(tenant_id, event_type, created_at desc);
create index if not exists idx_crm_queue_tenant_status on public.crm_webhook_queue(tenant_id, status, next_attempt_at);

do $$
declare
  table_name text;
begin
  foreach table_name in array array[
    'products', 'timelines', 'video_explanations', 'question_videos',
    'scoreline_schools', 'scoreline_majors', 'scoreline_fields', 'scoreline_records',
    'referral_tracks', 'badges', 'user_badges', 'crm_webhook_queue', 'crm_webhook_log'
  ]
  loop
    execute format('alter table public.%I enable row level security', table_name);
    execute format('drop policy if exists tenant_isolation on public.%I', table_name);
    execute format(
      'create policy tenant_isolation on public.%I for all using (tenant_id = app.current_tenant_id() or app.is_platform_admin()) with check (tenant_id = app.current_tenant_id() or app.is_platform_admin())',
      table_name
    );
    execute format('drop trigger if exists set_updated_at on public.%I', table_name);
    execute format('create trigger set_updated_at before update on public.%I for each row execute function app.touch_updated_at()', table_name);
  end loop;
end $$;
