-- =====================================================================
-- IDENTITY SCHEMA — Part 3: Plans, Subscriptions, Payments, Discounts
-- =====================================================================

SET search_path TO identity, public;

CREATE TYPE plan_scope         AS ENUM ('User','Tenant');
CREATE TYPE billing_period     AS ENUM ('Monthly','Quarterly','SemiAnnual','Annual','Lifetime','OneTime');
CREATE TYPE payment_gateway    AS ENUM ('ZarinPal','IdPay','Bazaar','Stripe','Balance','Manual');
CREATE TYPE payment_status     AS ENUM ('Pending','Succeeded','Failed','Refunded','Cancelled');
CREATE TYPE payment_action     AS ENUM ('PlanPurchase','BalanceCharge','ProjectRender','UserProject','StorageUpgrade','Other');
CREATE TYPE discount_kind      AS ENUM ('Percentage','FixedAmount','FreeMonths','RenderCredits');

-- ---------------------------------------------------------------------
-- plans — subscription tiers (FlatRender or tenant-defined)
-- ---------------------------------------------------------------------
CREATE TABLE plans (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id                   UUID REFERENCES tenants(id) ON DELETE CASCADE,
    -- NULL tenant_id = global plan available to all tenants

    scope                       plan_scope NOT NULL DEFAULT 'User',
    code                        TEXT NOT NULL,                  -- 'pro_monthly', 'business_annual'
    name                        TEXT NOT NULL,
    description                 TEXT,

    -- Pricing
    price_minor                 BIGINT NOT NULL DEFAULT 0,
    before_price_minor          BIGINT,                          -- shown crossed-out
    currency                    TEXT NOT NULL DEFAULT 'IRR',
    discount_percentage         NUMERIC(5,2) NOT NULL DEFAULT 0,

    billing_period              billing_period NOT NULL DEFAULT 'Monthly',
    months_duration             INT,                             -- for non-monthly

    -- Quotas
    seconds_charge              INT NOT NULL DEFAULT 0,          -- render seconds included
    monthly_renders_quota       INT,                             -- NULL = unlimited
    storage_gb                  INT NOT NULL DEFAULT 1,
    parallel_renders            INT NOT NULL DEFAULT 1,
    max_resolution              TEXT NOT NULL DEFAULT 'FullHD',
    min_video_length_sec        INT NOT NULL DEFAULT 0,
    render_speed_factor         NUMERIC(4,2) NOT NULL DEFAULT 1.0,

    -- UI
    sort                        INT NOT NULL DEFAULT 0,
    icon                        TEXT,
    cover                       TEXT,
    loyalty_mark                TEXT,
    color                       TEXT,
    is_featured                 BOOLEAN NOT NULL DEFAULT FALSE,

    -- Feature flags carried by this plan
    features                    JSONB NOT NULL DEFAULT '{}'::jsonb,

    -- Lifecycle
    is_active                   BOOLEAN NOT NULL DEFAULT TRUE,
    available_from              TIMESTAMPTZ,
    available_until             TIMESTAMPTZ,

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

    CONSTRAINT uq_plans_tenant_code UNIQUE (tenant_id, code)
);

CREATE INDEX idx_plans_tenant_active ON plans(tenant_id) WHERE is_active = TRUE AND deleted_at IS NULL;

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

-- ---------------------------------------------------------------------
-- user_plans — active subscriptions
-- ---------------------------------------------------------------------
CREATE TABLE user_plans (
    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,
    plan_id                     UUID NOT NULL REFERENCES plans(id),

    -- Snapshot at purchase time
    plan_code                   TEXT NOT NULL,
    plan_name                   TEXT NOT NULL,
    price_minor_paid            BIGINT NOT NULL,
    currency                    TEXT NOT NULL,

    -- Quota state
    initial_seconds_charge      INT NOT NULL,
    remain_charge_sec           INT NOT NULL,
    added_charge_from_past_plan INT NOT NULL DEFAULT 0,
    monthly_renders_used        INT NOT NULL DEFAULT 0,
    monthly_renders_reset_at    TIMESTAMPTZ,

    -- Lifecycle
    register_date               TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    starts_at                   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    expires_at                  TIMESTAMPTZ NOT NULL,
    cancelled_at                TIMESTAMPTZ,
    cancel_reason               TEXT,
    auto_renew                  BOOLEAN NOT NULL DEFAULT FALSE,

    -- Reference to payment
    payment_id                  UUID,

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

CREATE INDEX idx_user_plans_active ON user_plans(user_id) WHERE cancelled_at IS NULL;
CREATE INDEX idx_user_plans_expire ON user_plans(expires_at) WHERE cancelled_at IS NULL;

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

-- ---------------------------------------------------------------------
-- discounts — coupons / affiliate codes
-- ---------------------------------------------------------------------
CREATE TABLE discounts (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id                   UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    name                        TEXT NOT NULL,
    code                        CITEXT NOT NULL,
    kind                        discount_kind NOT NULL,
    value                       NUMERIC(14,2) NOT NULL,           -- percent or amount

    -- Affiliate split
    owner_user_id               UUID REFERENCES users(id) ON DELETE SET NULL,
    owner_profit_percentage     NUMERIC(5,2) NOT NULL DEFAULT 0,
    only_owner                  BOOLEAN NOT NULL DEFAULT FALSE,   -- usable only by owner

    -- Constraints
    max_use_count               INT,                              -- NULL = unlimited
    used_count                  INT NOT NULL DEFAULT 0,
    min_purchase_minor          BIGINT NOT NULL DEFAULT 0,
    applies_to_plan_ids         UUID[],

    starts_at                   TIMESTAMPTZ,
    expires_at                  TIMESTAMPTZ,
    is_active                   BOOLEAN NOT NULL DEFAULT TRUE,

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

    CONSTRAINT uq_discounts_tenant_code UNIQUE (tenant_id, code)
);

CREATE INDEX idx_discounts_active ON discounts(tenant_id) WHERE is_active = TRUE;
CREATE INDEX idx_discounts_owner  ON discounts(owner_user_id) WHERE owner_user_id IS NOT NULL;

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

-- ---------------------------------------------------------------------
-- used_discounts — usage log per user
-- ---------------------------------------------------------------------
CREATE TABLE used_discounts (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    discount_id                 UUID NOT NULL REFERENCES discounts(id) ON DELETE RESTRICT,
    user_id                     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    payment_id                  UUID,
    code                        CITEXT NOT NULL,
    amount_discounted_minor     BIGINT NOT NULL,
    use_date                    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    created_at                  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_used_discounts_user ON used_discounts(user_id, use_date DESC);

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

    gateway                     payment_gateway NOT NULL,
    status                      payment_status NOT NULL DEFAULT 'Pending',
    action                      payment_action NOT NULL,

    -- Amounts
    amount_minor                BIGINT NOT NULL,
    currency                    TEXT NOT NULL DEFAULT 'IRR',
    balance_reducer_minor       BIGINT NOT NULL DEFAULT 0,        -- portion paid from balance
    discount_value_minor        BIGINT NOT NULL DEFAULT 0,

    -- Gateway refs
    gateway_token               TEXT,
    gateway_order_id            TEXT,
    gateway_track_id            TEXT,
    gateway_response            JSONB,
    card_last4                  TEXT,
    card_hash                   TEXT,

    -- Description
    title                       TEXT,
    description                 TEXT,

    -- Affiliate
    owner_user_id               UUID REFERENCES users(id) ON DELETE SET NULL,
    affiliate_profit_minor      BIGINT NOT NULL DEFAULT 0,
    after_pay_score             NUMERIC(8,2) NOT NULL DEFAULT 0,

    -- Polymorphic product reference
    used_discount_id            UUID REFERENCES used_discounts(id),
    plan_id                     UUID REFERENCES plans(id),
    user_project_id             UUID,           -- FK added later if user_projects keeps existing
    render_job_id               UUID,
    product_id                  UUID,

    -- Lifecycle
    confirmed_at                TIMESTAMPTZ,
    failed_at                   TIMESTAMPTZ,
    failure_reason              TEXT,
    refunded_at                 TIMESTAMPTZ,
    refund_amount_minor         BIGINT,
    refund_reason               TEXT,

    -- Checkout/receipt
    checkouted                  BOOLEAN NOT NULL DEFAULT FALSE,
    checkout_date               TIMESTAMPTZ,
    checkout_recipe             TEXT,

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

CREATE INDEX idx_payments_user        ON payments(user_id, created_at DESC);
CREATE INDEX idx_payments_tenant      ON payments(tenant_id, created_at DESC);
CREATE INDEX idx_payments_status      ON payments(status) WHERE status IN ('Pending','Failed');
CREATE INDEX idx_payments_track       ON payments(gateway, gateway_track_id) WHERE gateway_track_id IS NOT NULL;

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

-- Now wire up the FKs that were dangling
ALTER TABLE used_discounts
  ADD CONSTRAINT fk_used_disc_payment
  FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE SET NULL;

ALTER TABLE user_plans
  ADD CONSTRAINT fk_user_plans_payment
  FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE SET NULL;

-- ---------------------------------------------------------------------
-- checkouts — receipts / affiliate payouts log
-- ---------------------------------------------------------------------
CREATE TABLE checkouts (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id                     UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
    tenant_id                   UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    affiliate_owner_id          UUID REFERENCES users(id) ON DELETE SET NULL,

    title                       TEXT,
    description                 TEXT,
    amount_minor                BIGINT NOT NULL,
    currency                    TEXT NOT NULL DEFAULT 'IRR',
    card_number_last4           TEXT,

    requested_at                TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    paid_at                     TIMESTAMPTZ,
    recipe                      TEXT,

    created_at                  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_checkouts_user ON checkouts(user_id, requested_at DESC);

-- ---------------------------------------------------------------------
-- user_projects — freelance custom-template requests
-- ---------------------------------------------------------------------
CREATE TYPE user_project_status AS ENUM (
    'Draft','Submitted','Quoted','InProgress','Review','Completed','Cancelled'
);

CREATE TABLE user_projects (
    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,

    title                           TEXT,
    description                     TEXT,
    graphist_description            TEXT,
    attachment_path                 TEXT,

    price_minor                     BIGINT,
    user_suggested_price_minor      BIGINT,
    status                          user_project_status NOT NULL DEFAULT 'Draft',

    user_max_requested_day_to_create        INT,
    user_graphist_max_requested_day_to_create INT,

    created_time                    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    end_time                        TIMESTAMPTZ,

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

CREATE INDEX idx_user_projects_user ON user_projects(user_id, status);

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

ALTER TABLE payments
  ADD CONSTRAINT fk_payments_user_project
  FOREIGN KEY (user_project_id) REFERENCES user_projects(id) ON DELETE SET NULL;
