BEGIN;

-- 1 user columns
ALTER TABLE "User"
  ADD COLUMN IF NOT EXISTS "signupSource" TEXT,
  ADD COLUMN IF NOT EXISTS "signupSourceSelfReported" TEXT,
  ADD COLUMN IF NOT EXISTS "signupMedium" TEXT,
  ADD COLUMN IF NOT EXISTS "signupCampaign" TEXT,
  ADD COLUMN IF NOT EXISTS "signupContent" TEXT,
  ADD COLUMN IF NOT EXISTS "signupTerm" TEXT,
  ADD COLUMN IF NOT EXISTS "signupReferrer" TEXT,
  ADD COLUMN IF NOT EXISTS "signupLandingPath" TEXT,
  ADD COLUMN IF NOT EXISTS "signupFirstSeenAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "emailDomain" TEXT,
  ADD COLUMN IF NOT EXISTS "primaryUseCase" TEXT,
  ADD COLUMN IF NOT EXISTS "primaryGoal" TEXT,
  ADD COLUMN IF NOT EXISTS "jobRole" TEXT,
  ADD COLUMN IF NOT EXISTS "companyName" TEXT,
  ADD COLUMN IF NOT EXISTS "companyWebsite" TEXT,
  ADD COLUMN IF NOT EXISTS "teamSizeBucket" TEXT,
  ADD COLUMN IF NOT EXISTS "onboardingStartedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "sourceConfirmedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "useCaseSelectedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "goalSelectedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "profileCompletedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "firstQrCreatedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "firstDynamicQrAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "firstStaticQrAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "firstScanAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "activationAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "onboardingCompletedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "fitScore" INTEGER NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS "intentScore" INTEGER NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS "leadScore" INTEGER NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS "lifecycleStage" TEXT NOT NULL DEFAULT 'cold',
  ADD COLUMN IF NOT EXISTS "lastQualifiedAt" TIMESTAMP(3),
  ADD COLUMN IF NOT EXISTS "lastScoredAt" TIMESTAMP(3);

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_constraint WHERE conname = 'User_lifecycleStage_check'
  ) THEN
    ALTER TABLE "User"
      ADD CONSTRAINT "User_lifecycleStage_check"
      CHECK ("lifecycleStage" IN (
        'cold',
        'activated',
        'warm',
        'hot',
        'upgrade_candidate',
        'paid'
      ));
  END IF;
END $$;

-- 2 lifecycle log table
CREATE TABLE IF NOT EXISTS "UserLifecycleLog" (
  "id" TEXT PRIMARY KEY,
  "userId" TEXT NOT NULL,
  "fromStage" TEXT,
  "toStage" TEXT NOT NULL,
  "fitScore" INTEGER NOT NULL DEFAULT 0,
  "intentScore" INTEGER NOT NULL DEFAULT 0,
  "leadScore" INTEGER NOT NULL DEFAULT 0,
  "reason" TEXT,
  "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT "UserLifecycleLog_userId_fkey"
    FOREIGN KEY ("userId") REFERENCES "User"("id")
    ON DELETE CASCADE ON UPDATE CASCADE
);

-- 3 indexes
CREATE INDEX IF NOT EXISTS "User_signupSource_idx" ON "User" ("signupSource");
CREATE INDEX IF NOT EXISTS "User_signupSourceSelfReported_idx" ON "User" ("signupSourceSelfReported");
CREATE INDEX IF NOT EXISTS "User_signupCampaign_idx" ON "User" ("signupCampaign");
CREATE INDEX IF NOT EXISTS "User_signupLandingPath_idx" ON "User" ("signupLandingPath");
CREATE INDEX IF NOT EXISTS "User_emailDomain_idx" ON "User" ("emailDomain");
CREATE INDEX IF NOT EXISTS "User_primaryUseCase_idx" ON "User" ("primaryUseCase");
CREATE INDEX IF NOT EXISTS "User_primaryGoal_idx" ON "User" ("primaryGoal");
CREATE INDEX IF NOT EXISTS "User_jobRole_idx" ON "User" ("jobRole");
CREATE INDEX IF NOT EXISTS "User_teamSizeBucket_idx" ON "User" ("teamSizeBucket");
CREATE INDEX IF NOT EXISTS "User_lifecycleStage_idx" ON "User" ("lifecycleStage");
CREATE INDEX IF NOT EXISTS "User_leadScore_idx" ON "User" ("leadScore" DESC);
CREATE INDEX IF NOT EXISTS "User_activationAt_idx" ON "User" ("activationAt");
CREATE INDEX IF NOT EXISTS "User_firstScanAt_idx" ON "User" ("firstScanAt");
CREATE INDEX IF NOT EXISTS "User_firstQrCreatedAt_idx" ON "User" ("firstQrCreatedAt");
CREATE INDEX IF NOT EXISTS "User_lastQualifiedAt_idx" ON "User" ("lastQualifiedAt");

CREATE INDEX IF NOT EXISTS "UserLifecycleLog_userId_idx" ON "UserLifecycleLog" ("userId");
CREATE INDEX IF NOT EXISTS "UserLifecycleLog_toStage_idx" ON "UserLifecycleLog" ("toStage");
CREATE INDEX IF NOT EXISTS "UserLifecycleLog_createdAt_idx" ON "UserLifecycleLog" ("createdAt" DESC);

-- 4 backfill
UPDATE "User"
SET "emailDomain" = lower(split_part("email", '@', 2))
WHERE "email" IS NOT NULL
  AND ("emailDomain" IS NULL OR "emailDomain" = '');

UPDATE "User" u
SET
  "firstQrCreatedAt" = q."firstQrAt",
  "firstDynamicQrAt" = q."firstDynamicQrAt",
  "firstStaticQrAt" = q."firstStaticQrAt",
  "onboardingCompletedAt" = COALESCE(u."onboardingCompletedAt", q."firstQrAt")
FROM (
  SELECT
    "userId",
    MIN("createdAt") AS "firstQrAt",
    MIN("createdAt") FILTER (WHERE "type" = 'DYNAMIC') AS "firstDynamicQrAt",
    MIN("createdAt") FILTER (WHERE "type" = 'STATIC') AS "firstStaticQrAt"
  FROM "QRCode"
  GROUP BY "userId"
) q
WHERE u."id" = q."userId";

UPDATE "User" u
SET
  "firstScanAt" = s."firstScanAt",
  "activationAt" = COALESCE(u."activationAt", s."firstScanAt")
FROM (
  SELECT
    q."userId",
    MIN(s."ts") AS "firstScanAt"
  FROM "QRCode" q
  INNER JOIN "QRScan" s ON s."qrId" = q."id"
  GROUP BY q."userId"
) s
WHERE u."id" = s."userId";

-- 5 scoring
WITH qr_stats AS (
  SELECT
    q."userId",
    COUNT(*) AS qr_count,
    COUNT(*) FILTER (WHERE q."type" = 'DYNAMIC') AS dynamic_count,
    COUNT(DISTINCT q."contentType") AS content_type_count,
    COUNT(*) FILTER (WHERE q."contentType" IN ('BARCODE','PDF','VCARD','COUPON','FEEDBACK')) AS businessish_type_count
  FROM "QRCode" q
  GROUP BY q."userId"
),
scan_stats AS (
  SELECT
    q."userId",
    COUNT(s."id") AS scan_count
  FROM "QRCode" q
  LEFT JOIN "QRScan" s ON s."qrId" = q."id"
  GROUP BY q."userId"
),
scored AS (
  SELECT
    u."id",
    COALESCE(qs.qr_count, 0) AS qr_count,
    COALESCE(qs.dynamic_count, 0) AS dynamic_count,
    COALESCE(qs.content_type_count, 0) AS content_type_count,
    COALESCE(qs.businessish_type_count, 0) AS businessish_type_count,
    COALESCE(ss.scan_count, 0) AS scan_count
  FROM "User" u
  LEFT JOIN qr_stats qs ON qs."userId" = u."id"
  LEFT JOIN scan_stats ss ON ss."userId" = u."id"
)
UPDATE "User" u
SET
  "fitScore" =
    (CASE
      WHEN lower(split_part(u."email", '@', 2)) IN ('gmail.com','yahoo.com','hotmail.com','outlook.com','icloud.com') THEN -15
      WHEN u."email" IS NOT NULL THEN 20
      ELSE 0
    END)
    +
    (CASE
      WHEN u."primaryUseCase" IN ('marketing_campaign','bulk_qr','menu_pdf','barcode') THEN 10
      ELSE 0
    END)
    +
    (CASE
      WHEN u."primaryGoal" IN ('track_printed_campaigns','generate_leads','manage_multiple_qr_codes') THEN 10
      ELSE 0
    END)
    +
    (CASE
      WHEN u."jobRole" IN ('founder_owner','marketing_manager','agency_freelancer','operations') THEN 10
      ELSE 0
    END)
    +
    (CASE
      WHEN u."companyName" IS NOT NULL AND u."companyName" <> '' THEN 5
      ELSE 0
    END)
    +
    (CASE
      WHEN u."teamSizeBucket" IN ('6_20','21_100','100_plus') THEN 10
      ELSE 0
    END),
  "intentScore" =
    (CASE WHEN u."firstQrCreatedAt" IS NOT NULL THEN 20 ELSE -10 END)
    +
    (CASE WHEN u."firstDynamicQrAt" IS NOT NULL THEN 20 ELSE 0 END)
    +
    (CASE WHEN COALESCE(s.qr_count, 0) >= 3 THEN 15 ELSE 0 END)
    +
    (CASE WHEN COALESCE(s.scan_count, 0) > 0 THEN 10 ELSE 0 END)
    +
    (CASE WHEN COALESCE(s.businessish_type_count, 0) > 0 THEN 10 ELSE 0 END)
    +
    (CASE WHEN COALESCE(s.content_type_count, 0) >= 2 THEN 10 ELSE 0 END),
  "lastScoredAt" = CURRENT_TIMESTAMP
FROM scored s
WHERE u."id" = s."id";

UPDATE "User"
SET "leadScore" = COALESCE("fitScore", 0) + COALESCE("intentScore", 0);

UPDATE "User"
SET
  "lifecycleStage" = CASE
    WHEN "plan" IN ('PRO','BUSINESS') THEN 'paid'
    WHEN "leadScore" >= 70 THEN 'upgrade_candidate'
    WHEN "leadScore" >= 55 THEN 'hot'
    WHEN "leadScore" >= 30 THEN 'warm'
    WHEN "activationAt" IS NOT NULL THEN 'activated'
    ELSE 'cold'
  END,
  "lastQualifiedAt" = CASE
    WHEN "leadScore" >= 55 OR "plan" IN ('PRO','BUSINESS') THEN CURRENT_TIMESTAMP
    ELSE "lastQualifiedAt"
  END;

-- 6 reporting queries
-- Acquisition overview
SELECT
  COALESCE("signupSource", 'unknown') AS source,
  COUNT(*) AS signups,
  COUNT(*) FILTER (WHERE "firstQrCreatedAt" IS NOT NULL) AS first_qr,
  COUNT(*) FILTER (WHERE "activationAt" IS NOT NULL) AS activated,
  COUNT(*) FILTER (WHERE "lifecycleStage" = 'hot') AS hot,
  COUNT(*) FILTER (WHERE "lifecycleStage" = 'upgrade_candidate') AS upgrade_candidates,
  COUNT(*) FILTER (WHERE "lifecycleStage" = 'paid') AS paid
FROM "User"
GROUP BY 1
ORDER BY signups DESC;

-- Onboarding funnel
SELECT
  COUNT(*) AS signup,
  COUNT(*) FILTER (WHERE "sourceConfirmedAt" IS NOT NULL) AS source_confirmed,
  COUNT(*) FILTER (WHERE "useCaseSelectedAt" IS NOT NULL) AS use_case_selected,
  COUNT(*) FILTER (WHERE "goalSelectedAt" IS NOT NULL) AS goal_selected,
  COUNT(*) FILTER (WHERE "profileCompletedAt" IS NOT NULL) AS profile_completed,
  COUNT(*) FILTER (WHERE "firstQrCreatedAt" IS NOT NULL) AS first_qr_created,
  COUNT(*) FILTER (WHERE "firstDynamicQrAt" IS NOT NULL) AS first_dynamic_qr_created,
  COUNT(*) FILTER (WHERE "activationAt" IS NOT NULL) AS activated
FROM "User";

-- Lifecycle summary
SELECT
  "lifecycleStage",
  COUNT(*) AS users
FROM "User"
GROUP BY 1
ORDER BY users DESC;

COMMIT;
