-- ===============================
-- ComplyCore Supabase IAM + RLS Init
-- Includes:
-- - Tenants
-- - Users
-- - Service Accounts (NPEs)
-- - Audit Logs
-- ===============================

-- 1. Define user roles
CREATE TYPE user_role AS ENUM ('client_user', 'client_admin', 'reviewer', 'superadmin');

-- 2. Define authentication scopes for service accounts
CREATE TYPE api_scope AS ENUM ('upload', 'evaluate', 'read_reports', 'manage_projects');

-- 3. Tenants table
CREATE TABLE tenants (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL,
  dba_name TEXT,
  cage_code TEXT,
  sam_uid TEXT,
  duns_number TEXT,
  naics_codes TEXT[],
  address_line1 TEXT,
  address_line2 TEXT,
  city TEXT,
  state_province TEXT,
  postal_code TEXT,
  country TEXT DEFAULT 'USA',
  primary_contact_name TEXT,
  primary_contact_email TEXT,
  primary_contact_phone TEXT,
  cmmc_target_level TEXT DEFAULT 'Level 2',
  sponsoring_agency TEXT,
  compliance_status TEXT DEFAULT 'pending',
  notes TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
);

-- 4. Users table (linked to auth.users)
CREATE TABLE users (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  tenant_id UUID NOT NULL REFERENCES tenants(id),
  role user_role NOT NULL DEFAULT 'client_user',

  -- Identity
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  job_title TEXT,
  department TEXT,

  -- Contact
  email TEXT NOT NULL UNIQUE,
  phone_office TEXT,
  phone_mobile TEXT,
  address_line1 TEXT,
  address_line2 TEXT,
  city TEXT,
  state_province TEXT,
  postal_code TEXT,
  country TEXT DEFAULT 'USA',

  -- Flags
  is_service_account BOOLEAN DEFAULT false,
  mfa_enabled BOOLEAN DEFAULT false,

  -- System
  last_login_at TIMESTAMP WITH TIME ZONE,
  notes TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
);

-- 5. Service Accounts (API Clients)
CREATE TABLE api_clients (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id),
  name TEXT NOT NULL,
  client_id TEXT NOT NULL UNIQUE,
  client_secret TEXT NOT NULL,
  scopes api_scope[] NOT NULL,
  enabled BOOLEAN DEFAULT true,
  created_by UUID REFERENCES users(id),
  description TEXT,
  last_used_at TIMESTAMP WITH TIME ZONE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
);

-- 6. Evaluation results table
CREATE TABLE evaluations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id),
  project_id UUID NOT NULL,
  control_id TEXT NOT NULL,
  status TEXT CHECK (status IN ('implemented', 'partial', 'missing')),
  notes TEXT,
  created_by UUID REFERENCES users(id),
  created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
);

-- 7. Audit log
CREATE TABLE auth_audit_log (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  actor_id UUID, -- user or service account
  tenant_id UUID NOT NULL REFERENCES tenants(id),
  action TEXT NOT NULL,
  target_table TEXT,
  target_id UUID,
  ip_address TEXT,
  user_agent TEXT,
  result TEXT CHECK (result IN ('success', 'fail')) DEFAULT 'success',
  timestamp TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc', now())
);

-- =======================================
-- Session Context Claims
-- =======================================

CREATE OR REPLACE FUNCTION set_claim_context()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
  v_role TEXT;
  v_tenant UUID;
BEGIN
  SELECT role, tenant_id INTO v_role, v_tenant
  FROM public.users
  WHERE id = auth.uid();

  -- Set session-scoped variables
  PERFORM set_config('request.jwt.claim.role', v_role, true);
  PERFORM set_config('request.jwt.claim.tenant_id', v_tenant::text, true);
END;
$$;

-- =======================================
-- Row-Level Security (RLS) Policies
-- =======================================

-- Enable RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE evaluations ENABLE ROW LEVEL SECURITY;
ALTER TABLE api_clients ENABLE ROW LEVEL SECURITY;
ALTER TABLE auth_audit_log ENABLE ROW LEVEL SECURITY;

-- Users: only see own row
CREATE POLICY "Self-access only"
  ON users
  USING (id = auth.uid());

-- Evaluations: Tenant isolation for client roles
CREATE POLICY "Tenant isolation"
  ON evaluations
  FOR ALL
  USING (
    (current_setting('request.jwt.claim.role', true) IN ('client_user', 'client_admin'))
    AND tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
  );

-- Evaluations: Reviewer read-only access
CREATE POLICY "Reviewer read access"
  ON evaluations
  FOR SELECT
  USING (
    current_setting('request.jwt.claim.role', true) = 'reviewer'
  );

-- Evaluations: Superadmin full access
CREATE POLICY "Superadmin full access"
  ON evaluations
  FOR ALL
  USING (
    current_setting('request.jwt.claim.role', true) = 'superadmin'
  )
  WITH CHECK (
    current_setting('request.jwt.claim.role', true) = 'superadmin'
  );

-- Service Accounts: Restrict to own tenant + enabled
CREATE POLICY "API client isolation"
  ON api_clients
  FOR ALL
  USING (
    tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
    AND enabled = true
  );

-- Audit Log: tenant-scoped visibility
CREATE POLICY "Audit tenant visibility"
  ON auth_audit_log
  FOR SELECT
  USING (
    tenant_id = current_setting('request.jwt.claim.tenant_id', true)::uuid
  );
