-- =====================================================================
-- IDENTITY SCHEMA — Part 1: Tenants (Multi-tenancy / Reseller API)
-- =====================================================================
-- Every user, project, render, export belongs to a tenant.
-- FlatRender's own customers belong to the DEFAULT tenant.
-- Resellers (B2B) are their own tenants with their own users.
-- =====================================================================

SET search_path TO identity, public;

-- ---------------------------------------------------------------------
-- tenants — companies / resellers (and FlatRender itself = default)
-- ---------------------------------------------------------------------
CREATE TYPE tenant_status AS ENUM ('Active','Trial','Suspended','Cancelled');
CREATE TYPE tenant_kind   AS ENUM ('Internal','Reseller','Enterprise');

CREATE TABLE tenants (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    slug                CITEXT UNIQUE NOT NULL,                  -- 'flatrender', 'acme', ...
    name                TEXT NOT NULL,
    kind                tenant_kind NOT NULL DEFAULT 'Reseller',
    status              tenant_status NOT NULL DEFAULT 'Trial',

    -- Domains
    custom_domain       CITEXT UNIQUE,                            -- videos.acme.com
    domain_verified     BOOLEAN NOT NULL DEFAULT FALSE,
    allowed_origins     TEXT[] NOT NULL DEFAULT '{}',             -- CORS

    -- Contact
    contact_name        TEXT,
    contact_email       CITEXT,
    contact_phone       TEXT,
    billing_email       CITEXT,

    -- Limits (overrideable from default plan)
    max_users           INT,                                       -- NULL = unlimited
    max_storage_gb      INT,
    monthly_render_qty  INT,
    monthly_render_sec  INT,

    -- Lifecycle
    trial_ends_at       TIMESTAMPTZ,
    suspended_at        TIMESTAMPTZ,
    suspension_reason   TEXT,

    -- Metadata
    metadata            JSONB NOT NULL DEFAULT '{}'::jsonb,

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at          TIMESTAMPTZ
);

CREATE INDEX idx_tenants_status        ON tenants(status) WHERE deleted_at IS NULL;
CREATE INDEX idx_tenants_custom_domain ON tenants(custom_domain) WHERE custom_domain IS NOT NULL;

CREATE TRIGGER tg_tenants_updated_at
BEFORE UPDATE ON tenants
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- Seed the default (internal) FlatRender tenant
INSERT INTO tenants (id, slug, name, kind, status)
VALUES (
    '00000000-0000-0000-0000-000000000001',
    'flatrender',
    'FlatRender',
    'Internal',
    'Active'
);

-- ---------------------------------------------------------------------
-- tenant_branding — white-label appearance
-- ---------------------------------------------------------------------
CREATE TABLE tenant_branding (
    tenant_id           UUID PRIMARY KEY REFERENCES tenants(id) ON DELETE CASCADE,

    -- Identity
    display_name        TEXT,
    logo_url            TEXT,
    logo_dark_url       TEXT,
    favicon_url         TEXT,
    og_image_url        TEXT,

    -- Theme
    primary_color       TEXT NOT NULL DEFAULT '#3B82F6',
    secondary_color     TEXT NOT NULL DEFAULT '#8B5CF6',
    accent_color        TEXT,
    background_color    TEXT,
    font_family         TEXT,

    -- Email
    email_from_name     TEXT,
    email_from_address  CITEXT,
    email_reply_to      CITEXT,
    email_footer_html   TEXT,

    -- Links
    support_url         TEXT,
    terms_url           TEXT,
    privacy_url         TEXT,

    -- Studio embed
    embed_enabled       BOOLEAN NOT NULL DEFAULT FALSE,
    embed_allowed_hosts TEXT[] NOT NULL DEFAULT '{}',

    -- Custom CSS for advanced clients (sanitized)
    custom_css          TEXT,

    -- Watermark for free renders (reseller can override)
    watermark_text      TEXT,
    watermark_image_url TEXT,
    watermark_enabled   BOOLEAN NOT NULL DEFAULT TRUE,

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TRIGGER tg_tenant_branding_updated_at
BEFORE UPDATE ON tenant_branding
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- ---------------------------------------------------------------------
-- tenant_settings — feature flags + integration config
-- ---------------------------------------------------------------------
CREATE TABLE tenant_settings (
    tenant_id              UUID PRIMARY KEY REFERENCES tenants(id) ON DELETE CASCADE,

    -- Locale
    default_locale         TEXT NOT NULL DEFAULT 'fa',
    supported_locales      TEXT[] NOT NULL DEFAULT '{fa,en}',
    default_currency       TEXT NOT NULL DEFAULT 'IRR',

    -- Payments allowed for this tenant's users
    payment_gateways       TEXT[] NOT NULL DEFAULT '{ZarinPal}',    -- {ZarinPal,IdPay,Bazaar,Stripe}

    -- Render
    max_resolution         TEXT NOT NULL DEFAULT 'FullHD',          -- HD/FullHD/FourK
    max_duration_sec       INT NOT NULL DEFAULT 600,
    allow_4k               BOOLEAN NOT NULL DEFAULT FALSE,
    allow_voiceover        BOOLEAN NOT NULL DEFAULT TRUE,
    allow_music_visualizer BOOLEAN NOT NULL DEFAULT TRUE,
    allow_mockup           BOOLEAN NOT NULL DEFAULT TRUE,

    -- Webhooks
    webhook_signing_secret TEXT,

    -- Feature flags
    features               JSONB NOT NULL DEFAULT '{}'::jsonb,

    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TRIGGER tg_tenant_settings_updated_at
BEFORE UPDATE ON tenant_settings
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- ---------------------------------------------------------------------
-- tenant_api_keys — server-to-server API access
-- ---------------------------------------------------------------------
CREATE TYPE api_key_environment AS ENUM ('Live','Test');

CREATE TABLE tenant_api_keys (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    name                TEXT NOT NULL,                              -- "Production server"
    environment         api_key_environment NOT NULL DEFAULT 'Live',

    -- Storage
    key_prefix          TEXT NOT NULL,                              -- "fr_live_abc..." (first 12 chars visible)
    key_hash            TEXT NOT NULL,                              -- SHA-256 of full key
    last4               TEXT NOT NULL,                              -- last 4 chars for UI

    -- Permissions
    scopes              TEXT[] NOT NULL DEFAULT '{}',               -- ["renders:create","projects:read",...]
    allowed_ips         INET[],                                     -- NULL = any
    rate_limit_rpm      INT NOT NULL DEFAULT 600,

    -- Lifecycle
    is_active           BOOLEAN NOT NULL DEFAULT TRUE,
    expires_at          TIMESTAMPTZ,
    revoked_at          TIMESTAMPTZ,
    revoked_reason      TEXT,
    last_used_at        TIMESTAMPTZ,
    last_used_ip        INET,
    usage_count         BIGINT NOT NULL DEFAULT 0,

    created_by_user_id  UUID,                                       -- FK added after users table exists
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE UNIQUE INDEX uq_api_keys_hash ON tenant_api_keys(key_hash);
CREATE INDEX idx_api_keys_tenant     ON tenant_api_keys(tenant_id) WHERE is_active = TRUE;
CREATE INDEX idx_api_keys_prefix     ON tenant_api_keys(key_prefix);

CREATE TRIGGER tg_tenant_api_keys_updated_at
BEFORE UPDATE ON tenant_api_keys
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- ---------------------------------------------------------------------
-- tenant_webhooks — outbound events to reseller systems
-- ---------------------------------------------------------------------
CREATE TABLE tenant_webhooks (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    name                TEXT NOT NULL,
    url                 TEXT NOT NULL,
    events              TEXT[] NOT NULL,                            -- ["render.completed","render.failed",...]
    secret              TEXT NOT NULL,                              -- HMAC signing secret

    is_active           BOOLEAN NOT NULL DEFAULT TRUE,
    last_triggered_at   TIMESTAMPTZ,
    last_status_code    INT,
    consecutive_failures INT NOT NULL DEFAULT 0,
    disabled_at         TIMESTAMPTZ,                                -- auto-disable after N failures

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_webhooks_tenant_active ON tenant_webhooks(tenant_id) WHERE is_active = TRUE;

CREATE TRIGGER tg_tenant_webhooks_updated_at
BEFORE UPDATE ON tenant_webhooks
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- ---------------------------------------------------------------------
-- tenant_webhook_deliveries — log of attempts
-- ---------------------------------------------------------------------
CREATE TABLE tenant_webhook_deliveries (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    webhook_id          UUID NOT NULL REFERENCES tenant_webhooks(id) ON DELETE CASCADE,
    tenant_id           UUID NOT NULL,                              -- denormalized for partitioning

    event_type          TEXT NOT NULL,
    event_id            UUID NOT NULL,
    payload             JSONB NOT NULL,

    request_url         TEXT NOT NULL,
    response_status     INT,
    response_body       TEXT,
    duration_ms         INT,

    attempt             INT NOT NULL DEFAULT 1,
    succeeded           BOOLEAN NOT NULL DEFAULT FALSE,
    next_retry_at       TIMESTAMPTZ,
    error_message       TEXT,

    delivered_at        TIMESTAMPTZ,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_webhook_deliveries_webhook  ON tenant_webhook_deliveries(webhook_id, created_at DESC);
CREATE INDEX idx_webhook_deliveries_pending  ON tenant_webhook_deliveries(next_retry_at) WHERE succeeded = FALSE AND next_retry_at IS NOT NULL;

-- ---------------------------------------------------------------------
-- tenant_usage_daily — aggregate metering for billing the reseller
-- ---------------------------------------------------------------------
CREATE TABLE tenant_usage_daily (
    id                  BIGSERIAL PRIMARY KEY,
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    usage_date          DATE NOT NULL,

    -- Render
    renders_started     INT NOT NULL DEFAULT 0,
    renders_completed   INT NOT NULL DEFAULT 0,
    renders_failed      INT NOT NULL DEFAULT 0,
    render_seconds      BIGINT NOT NULL DEFAULT 0,                  -- output duration sum
    render_compute_sec  BIGINT NOT NULL DEFAULT 0,                  -- node compute time

    -- Storage
    storage_bytes       BIGINT NOT NULL DEFAULT 0,                  -- snapshot at end of day

    -- API
    api_calls           BIGINT NOT NULL DEFAULT 0,
    api_4xx             BIGINT NOT NULL DEFAULT 0,
    api_5xx             BIGINT NOT NULL DEFAULT 0,

    -- Users
    active_users        INT NOT NULL DEFAULT 0,                     -- DAU
    new_users           INT NOT NULL DEFAULT 0,

    -- Billing
    amount_billed       NUMERIC(14,2) NOT NULL DEFAULT 0,
    billing_currency    TEXT NOT NULL DEFAULT 'IRR',
    billing_status      TEXT NOT NULL DEFAULT 'Pending',            -- Pending/Invoiced/Paid

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    UNIQUE (tenant_id, usage_date)
);

CREATE INDEX idx_tenant_usage_tenant_date ON tenant_usage_daily(tenant_id, usage_date DESC);

CREATE TRIGGER tg_tenant_usage_updated_at
BEFORE UPDATE ON tenant_usage_daily
FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();

-- ---------------------------------------------------------------------
-- tenant_api_request_logs — per-call audit (partitioned by month)
-- ---------------------------------------------------------------------
CREATE TABLE tenant_api_request_logs (
    id                  BIGSERIAL,
    tenant_id           UUID NOT NULL,
    api_key_id          UUID,

    method              TEXT NOT NULL,
    path                TEXT NOT NULL,
    status_code         INT NOT NULL,
    duration_ms         INT NOT NULL,

    request_id          UUID NOT NULL,
    user_id             UUID,
    ip_address          INET,
    user_agent          TEXT,

    error_message       TEXT,

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

CREATE INDEX idx_api_logs_tenant ON tenant_api_request_logs(tenant_id, created_at DESC);
CREATE INDEX idx_api_logs_key    ON tenant_api_request_logs(api_key_id, created_at DESC);

-- Initial partition (ops creates monthly going forward)
CREATE TABLE tenant_api_request_logs_y2026m01
    PARTITION OF tenant_api_request_logs
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

-- ---------------------------------------------------------------------
-- tenant_domain_verifications — DNS / file verification
-- ---------------------------------------------------------------------
CREATE TABLE tenant_domain_verifications (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    domain              CITEXT NOT NULL,
    method              TEXT NOT NULL,                              -- 'DNS_TXT' or 'HTTP_FILE'
    challenge_token     TEXT NOT NULL,
    verified            BOOLEAN NOT NULL DEFAULT FALSE,
    verified_at         TIMESTAMPTZ,
    last_checked_at     TIMESTAMPTZ,
    expires_at          TIMESTAMPTZ NOT NULL,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_domain_verif_tenant ON tenant_domain_verifications(tenant_id);
