alter table public.content_assets
  add column if not exists security_scan_status text not null default 'not_required',
  add column if not exists security_scanned_at timestamptz,
  add column if not exists security_scan_provider text,
  add column if not exists security_scan_summary jsonb not null default '{}'::jsonb;

update public.content_assets
set security_scan_status = case
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        and upload_status = 'verified'
        then 'passed'
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        and upload_status = 'failed'
        then 'skipped'
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        then 'pending'
      else 'not_required'
    end,
    security_scanned_at = case
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        and upload_status = 'verified'
        then coalesce(security_scanned_at, verified_at, updated_at, created_at, now())
      else security_scanned_at
    end,
    security_scan_provider = case
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        and upload_status = 'verified'
        then coalesce(security_scan_provider, 'legacy_backfill')
      else security_scan_provider
    end,
    security_scan_summary = case
      when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
        and object_key is not null
        and upload_status = 'verified'
        then coalesce(security_scan_summary, '{}'::jsonb)
          || jsonb_build_object(
            'riskLevel', 'none',
            'issueCodes', '[]'::jsonb,
            'backfilled', true,
            'backfilledAt', now()
          )
      else coalesce(security_scan_summary, '{}'::jsonb)
    end
where security_scan_status = 'not_required'
   or security_scan_summary = '{}'::jsonb;

do $$
begin
  if not exists (select 1 from pg_constraint where conname = 'content_assets_security_scan_status_check') then
    alter table public.content_assets
      add constraint content_assets_security_scan_status_check
      check (security_scan_status in ('not_required', 'pending', 'scanning', 'passed', 'failed', 'skipped'));
  end if;
end $$;

create table if not exists public.content_asset_security_scan_events (
  id uuid primary key default gen_random_uuid(),
  tenant_id uuid not null references public.tenants(id) on delete cascade,
  asset_id uuid references public.content_assets(id) on delete set null,
  provider text not null,
  scan_status text not null
    check (scan_status in ('pending', 'scanning', 'passed', 'failed', 'skipped')),
  risk_level text not null default 'none'
    check (risk_level in ('none', 'low', 'medium', 'high', 'critical')),
  issue_codes text[] not null default '{}',
  details jsonb not null default '{}'::jsonb,
  created_at timestamptz not null default now()
);

comment on table public.content_asset_security_scan_events is
  '内容资源安全扫描事件。用于记录托管对象的内置规则扫描、杀毒/内容安全 provider 扫描结果、失败原因和审计轨迹。';

create index if not exists idx_asset_security_scan_events_asset
  on public.content_asset_security_scan_events(tenant_id, asset_id, created_at desc);

create index if not exists idx_asset_security_scan_events_status
  on public.content_asset_security_scan_events(tenant_id, scan_status, risk_level, created_at desc);

create index if not exists idx_content_assets_security_scan_status
  on public.content_assets(tenant_id, security_scan_status, upload_status, status, updated_at desc);

alter table public.content_asset_security_scan_events enable row level security;

drop policy if exists tenant_isolation on public.content_asset_security_scan_events;
create policy tenant_isolation on public.content_asset_security_scan_events
  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());
