-- =====================================================================
-- IDENTITY SCHEMA — Part 2: Users, Auth, Sessions
-- =====================================================================

SET search_path TO identity, public;

CREATE TYPE register_mode AS ENUM ('Email','Mobile','Google','Telegram','SSO','Reseller');
CREATE TYPE gender_kind   AS ENUM ('Male','Female','Other','PreferNotToSay');

-- ---------------------------------------------------------------------
-- users
-- ---------------------------------------------------------------------
CREATE TABLE users (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id                   UUID NOT NULL REFERENCES tenants(id) ON DELETE RESTRICT,

    -- Auth
    email                       CITEXT,
    email_verified              BOOLEAN NOT NULL DEFAULT FALSE,
    email_verified_at           TIMESTAMPTZ,

    phone_number                TEXT,
    phone_country_code          TEXT,
    phone_verified              BOOLEAN NOT NULL DEFAULT FALSE,
    phone_verified_at           TIMESTAMPTZ,

    password_hash               TEXT,                          -- bcrypt; NULL for OAuth-only
    password_set_at             TIMESTAMPTZ,
    last_password_reset_date    TIMESTAMPTZ,

    register_mode               register_mode NOT NULL DEFAULT 'Email',
    external_provider           TEXT,                          -- google_oauth_subject etc.
    external_provider_id        TEXT,

    -- Profile
    full_name                   TEXT,
    avatar_url                  TEXT,
    birth_date                  DATE,
    gender                      gender_kind,
    national_code               TEXT,                          -- Iran-specific
    country_code                TEXT,
    company_name                TEXT,
    website_name                TEXT,
    slogan                      TEXT,
    about_me                    TEXT,
    method_of_introduction      TEXT,

    -- Balances (cents/rial; use BIGINT to avoid float)
    balance_minor               BIGINT NOT NULL DEFAULT 0,
    affiliate_balance_minor     BIGINT NOT NULL DEFAULT 0,
    affiliate_owner_id          UUID REFERENCES users(id) ON DELETE SET NULL,
    profit_percentage           NUMERIC(5,2) NOT NULL DEFAULT 0,

    -- Gamification (kept lean)
    loyalty_score               INT NOT NULL DEFAULT 0,
    purple_point                INT NOT NULL DEFAULT 0,

    -- Render quotas (computed from plan + bonuses)
    daily_remain_render_count   INT NOT NULL DEFAULT 0,
    max_daily_render_count      INT NOT NULL DEFAULT 0,
    parallel_rendering_ceiling  INT NOT NULL DEFAULT 1,
    user_daily_free_charge_sec  INT NOT NULL DEFAULT 0,
    daily_free_charge_reset_date TIMESTAMPTZ,
    max_preview_duration_sec    INT NOT NULL DEFAULT 30,
    force_render_queue          BOOLEAN NOT NULL DEFAULT FALSE,
    remove_watermark_service    BOOLEAN NOT NULL DEFAULT FALSE,

    -- Telegram (legacy but kept)
    telegram_id                 TEXT,
    telegram_token              TEXT,
    telegram_token_expire_date  TIMESTAMPTZ,
    telegram_tell_me            BOOLEAN NOT NULL DEFAULT FALSE,
    telegram_reset_date         TIMESTAMPTZ,
    user_telegram_charge        INT NOT NULL DEFAULT 0,

    -- Comms preferences
    email_tell_me               BOOLEAN NOT NULL DEFAULT TRUE,
    sms_tell_me                 BOOLEAN NOT NULL DEFAULT FALSE,
    push_tell_me                BOOLEAN NOT NULL DEFAULT TRUE,

    -- Storage
    storage_endpoint            TEXT,
    used_storage_bytes          BIGINT NOT NULL DEFAULT 0,

    -- Status
    is_admin                    BOOLEAN NOT NULL DEFAULT FALSE,
    is_tenant_admin             BOOLEAN NOT NULL DEFAULT FALSE,  -- admin within a tenant
    ban_account                 BOOLEAN NOT NULL DEFAULT FALSE,
    ban_reason                  TEXT,
    unblock_date                TIMESTAMPTZ,

    -- Activity
    last_active_date            TIMESTAMPTZ,
    last_login_at               TIMESTAMPTZ,
    last_login_ip               INET,
    registered_with_mobile_app  BOOLEAN NOT NULL DEFAULT FALSE,
    register_date               TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    -- Misc
    cid                         TEXT,                          -- legacy
    metadata                    JSONB NOT NULL DEFAULT '{}'::jsonb,

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

    -- Uniqueness scoped to tenant (so two tenants can have user@x.com independently)
    CONSTRAINT uq_users_tenant_email UNIQUE (tenant_id, email),
    CONSTRAINT uq_users_tenant_phone UNIQUE (tenant_id, phone_number),
    CONSTRAINT uq_users_external     UNIQUE (external_provider, external_provider_id)
);

CREATE INDEX idx_users_tenant         ON users(tenant_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_email          ON users(email) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_affiliate      ON users(affiliate_owner_id) WHERE affiliate_owner_id IS NOT NULL;
CREATE INDEX idx_users_last_active    ON users(last_active_date DESC);
CREATE INDEX idx_users_fullname_trgm  ON users USING gin (full_name gin_trgm_ops);

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

-- Now fix FK from tenant_api_keys.created_by_user_id
ALTER TABLE tenant_api_keys
  ADD CONSTRAINT fk_api_keys_creator
  FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL;

-- ---------------------------------------------------------------------
-- user_sessions — JWT refresh tokens / device tracking
-- ---------------------------------------------------------------------
CREATE TABLE user_sessions (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    refresh_token_hash  TEXT NOT NULL,
    device_id           TEXT,
    device_name         TEXT,
    user_agent          TEXT,
    ip_address          INET,

    issued_at           TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    expires_at          TIMESTAMPTZ NOT NULL,
    revoked_at          TIMESTAMPTZ,
    last_used_at        TIMESTAMPTZ
);

CREATE UNIQUE INDEX uq_sessions_token ON user_sessions(refresh_token_hash);
CREATE INDEX idx_sessions_user        ON user_sessions(user_id) WHERE revoked_at IS NULL;

-- ---------------------------------------------------------------------
-- confirmation_tokens — email/phone verify, password reset, MFA
-- ---------------------------------------------------------------------
CREATE TYPE token_purpose AS ENUM (
    'EmailVerification','PhoneVerification',
    'PasswordReset','MfaSetup','Login','EmailChange'
);

CREATE TABLE confirmation_tokens (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID REFERENCES users(id) ON DELETE CASCADE,
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    purpose             token_purpose NOT NULL,

    identifier          CITEXT NOT NULL,                 -- email or phone being verified
    next_identifier     CITEXT,                          -- for email change

    token_hash          TEXT NOT NULL,
    code                TEXT,                            -- 6-digit OTP (hashed in token_hash)

    is_consumed         BOOLEAN NOT NULL DEFAULT FALSE,
    consumed_at         TIMESTAMPTZ,
    try_count           INT NOT NULL DEFAULT 0,
    max_tries           INT NOT NULL DEFAULT 5,

    request_ip          INET,
    expires_at          TIMESTAMPTZ NOT NULL,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_conf_tokens_user    ON confirmation_tokens(user_id, purpose) WHERE is_consumed = FALSE;
CREATE INDEX idx_conf_tokens_lookup  ON confirmation_tokens(token_hash) WHERE is_consumed = FALSE;

-- ---------------------------------------------------------------------
-- push_subscriptions — PWA Web Push
-- ---------------------------------------------------------------------
CREATE TABLE push_subscriptions (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    tenant_id           UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    endpoint            TEXT NOT NULL,
    p256dh_key          TEXT NOT NULL,
    auth_key            TEXT NOT NULL,
    user_agent          TEXT,

    is_active           BOOLEAN NOT NULL DEFAULT TRUE,
    last_used_at        TIMESTAMPTZ,
    failure_count       INT NOT NULL DEFAULT 0,
    last_failure_at     TIMESTAMPTZ,
    last_failure_status INT,

    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    UNIQUE (user_id, endpoint)
);

CREATE INDEX idx_push_subs_user_active ON push_subscriptions(user_id) WHERE is_active = TRUE;

-- ---------------------------------------------------------------------
-- mfa_factors — TOTP, SMS, recovery codes
-- ---------------------------------------------------------------------
CREATE TYPE mfa_factor_type AS ENUM ('TOTP','SMS','Email','RecoveryCode');

CREATE TABLE mfa_factors (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    factor_type         mfa_factor_type NOT NULL,
    secret_encrypted    TEXT,
    is_verified         BOOLEAN NOT NULL DEFAULT FALSE,
    is_primary          BOOLEAN NOT NULL DEFAULT FALSE,
    label               TEXT,
    last_used_at        TIMESTAMPTZ,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_mfa_user ON mfa_factors(user_id) WHERE is_verified = TRUE;
