generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

enum UserRole {
  SUPERADMIN
  ADMIN
  SUBADMIN
  USER
}

enum ShopStatus {
  PENDING
  APPROVED
  REJECTED
}

enum LoyaltyProgramType {
  PERCENTAGE
  INCREMENTAL
}

enum LoyaltyEarnType {
  PERCENTAGE
  INCREMENTAL
}

enum CouponStatus {
  DRAFT
  ACTIVE
  EXPIRED
}

enum CouponValueType {
  FIXED
  PERCENTAGE
}

enum LuckyDrawStatus {
  DRAFT
  ACTIVE
  UPCOMING
  ENDED
}

enum DesignTemplateScope {
  COUPON
  LUCKY_DRAW
  ANY
}

enum ModerationStatus {
  DRAFT
  SUBMITTED
  PUBLISHED
  REJECTED
}

enum SaleStatus {
  COMPLETED
  PENDING
  CANCELLED
}

enum ReviewSource {
  CASHI
  GOOGLE
}

enum ReviewGoogleStatus {
  NOT_POSTED
  POSTED
  REMOVED
}

enum ReviewCashiStatus {
  NOT_POSTED
  POSTED
  REMOVED
}

enum PaymentGateway {
  EASEBUZZ
}

enum WalletTxnType {
  TOPUP
  DEBIT
}

enum WalletTxnStatus {
  PENDING
  SUCCESS
  FAILED
}

model User {
  id           String    @id @default(cuid())
  role         UserRole  @default(USER)
  email        String?   @unique
  phone        String?   @unique
  name         String?
  /// Cashi Coins wallet (earned from savings on sales; used to claim coupons).
  cashiCoins   Int       @default(0) @map("cashi_coins")
  /// Cashi Points (loyalty points). 1 point = ₹1.
  /// Stored separately for fast dashboard fetch (while still keeping grant-level expiry records).
  cashiPoints  Int       @default(0) @map("cashi_points")
  /// Last reported device position (customer app home refresh).
  latitude     Float?
  longitude    Float?
  /// Reverse-geocoded address label for the last saved coordinates (customer app).
  locationAddress String?
  passwordHash String?
  tokenVersion Int       @default(0)
  isActive     Boolean   @default(true)
  deactivatedAt DateTime?

  /// Customer app: unique shareable code (e.g. CASHI-XXXXXX).
  referralCode     String? @unique
  referredByUserId String?
  referredBy       User?   @relation("UserReferrals", fields: [referredByUserId], references: [id])
  referredUsers    User[]  @relation("UserReferrals")

  shopId String?
  shop   Shop?   @relation(fields: [shopId], references: [id])

  // For SUBADMIN: feature flags / access control (array of permission keys).
  // Null/empty means "no extra permissions" and only shop assignment applies.
  permissions Json?

  ownedShops Shop[] @relation("ShopAdmin")
  subadminShops SubadminShop[]
  customerShops CustomerShop[]
  customerSales Sale[] @relation("SaleCustomer")
  customerCoupons CustomerCoupon[]
  submittedReviews Review[] @relation("ReviewCustomer")
  passwordResetTokens PasswordResetToken[]
  loyaltyPointGrants LoyaltyPointGrant[]
  walletTransactions WalletTransaction[]
  paymentAttempts PaymentAttempt[]
  adminSubscription AdminSubscription?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([role, isActive, createdAt])
  @@map("users")
}

model SubadminShop {
  userId String
  shopId String

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)

  createdAt DateTime @default(now())

  @@id([userId, shopId])
  @@index([shopId])
  @@map("subadmin_shops")
}

model CustomerShop {
  userId String
  shopId String

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)

  firstSeenAt DateTime @default(now())
  lastSeenAt  DateTime @default(now())

  @@id([userId, shopId])
  @@index([shopId])
  @@map("customer_shops")
}

model BusinessType {
  id String @id @default(cuid())
  label String @unique
  imageUrl String?
  isActive Boolean @default(true)

  shops Shop[]

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("business_types")
}

model Shop {
  id      String @id @default(cuid())
  name    String
  username String? @unique
  address String
  city    String
  state   String
  pincode String
  gstNo   String?
  upiId   String?
  imageUrl String?
  latitude  Float?
  longitude Float?

  businessTypeId String?
  businessType BusinessType? @relation(fields: [businessTypeId], references: [id])

  // Integrations (stored per shop)
  googleApiKey  String?
  googlePlaceId String?
  facebookAppId String?
  facebookAppSecret String?
  instagramAccessToken String?
  instagramBusinessAccountId String?

  status     ShopStatus @default(PENDING)
  approvedAt DateTime?
  rejectedAt DateTime?
  rejectedReason String?
  isActive   Boolean    @default(true)
  deactivatedAt DateTime?

  // Stored wallet balance in INR (integer rupees).
  walletBalance Int @default(0)

  adminId String
  admin   User   @relation("ShopAdmin", fields: [adminId], references: [id])

  users User[]
  subadmins SubadminShop[]
  customers CustomerShop[]
  loyaltyPrograms LoyaltyProgram[]
  loyaltySettings LoyaltySettings?
  loyaltyPointGrants LoyaltyPointGrant[]
  coupons Coupon[]
  luckyDraws LuckyDraw[]
  designTemplates DesignTemplate[]
  sales Sale[]
  reviews Review[]
  walletTransactions WalletTransaction[]
  paymentAttempts PaymentAttempt[]

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([adminId, createdAt])
  @@index([status, createdAt])
  @@index([isActive, createdAt])
  @@index([status, isActive, createdAt])
  @@map("shops")
}

model AdminSubscription {
  id String @id @default(cuid())

  adminId String @unique
  admin   User   @relation(fields: [adminId], references: [id], onDelete: Cascade)

  planId String
  plan   Plan   @relation(fields: [planId], references: [id])

  /// Paid-plan expiry timestamp (NULL for free/basic).
  planExpiresAt DateTime?

  /// Optional scheduled downgrade (currently used for paid → free at end-of-cycle).
  scheduledPlanCode String?
  scheduledPlanAt   DateTime?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([planExpiresAt])
  @@index([scheduledPlanAt])
  @@map("admin_subscriptions")
}

model WalletTransaction {
  id String @id @default(cuid())

  shopId String
  shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)

  userId String?
  user User? @relation(fields: [userId], references: [id], onDelete: SetNull)

  type WalletTxnType
  status WalletTxnStatus @default(PENDING)

  // INR in rupees (integer)
  amount Int
  currency String @default("INR")

  purpose String?
  referenceId String?
  meta Json?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@index([referenceId])
  @@map("wallet_transactions")
}

model PaymentAttempt {
  id String @id @default(cuid())

  gateway PaymentGateway @default(EASEBUZZ)
  status WalletTxnStatus @default(PENDING)

  // Easebuzz txnid
  txnid String @unique

  shopId String
  shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)

  userId String?
  user User? @relation(fields: [userId], references: [id], onDelete: SetNull)

  // INR in rupees (integer)
  amount Int
  currency String @default("INR")

  purpose String?
  planCode String?

  rawRequest Json?
  rawResponse Json?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@map("payment_attempts")
}

model Review {
  id String @id @default(cuid())

  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id], onDelete: Cascade)

  customerUserId String?
  customerUser   User?   @relation("ReviewCustomer", fields: [customerUserId], references: [id], onDelete: SetNull)

  source ReviewSource @default(CASHI)

  category      String?
  customerName  String
  customerPhone String?

  rating  Int
  comment String

  googleStatus ReviewGoogleStatus @default(NOT_POSTED)
  googleExternalId String?
  googlePostDate   DateTime?

  cashiStatus ReviewCashiStatus @default(NOT_POSTED)
  cashiPostDate DateTime?

  response String?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@index([shopId, category, createdAt])
  @@index([customerUserId, createdAt])
  @@map("reviews")
}

model Sale {
  id String @id @default(cuid())

  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id])

  customerId String
  customer   User   @relation("SaleCustomer", fields: [customerId], references: [id])

  amount Int
  originalAmount Int?
  discountAmount Int @default(0)
  appliedCouponId String?
  appliedCoupon Coupon? @relation("SaleAppliedCoupon", fields: [appliedCouponId], references: [id], onDelete: SetNull)
  redeemedCoupons CustomerCoupon[] @relation("RedeemedSale")
  loyaltyPointsRedeemed Int @default(0)
  loyaltyPointsEarned   Int @default(0)
  /// Cashi Coins earned for this sale (saved amount).
  cashiCoinsEarned      Int @default(0) @map("cashi_coins_earned")
  loyaltyGrants LoyaltyPointGrant[]
  loyaltyUsages LoyaltyPointUsage[]
  customerLat Float?
  customerLng Float?
  notes  String?
  status SaleStatus @default(COMPLETED)

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@index([customerId, createdAt])
  @@map("sales")
}

model LoyaltyPointGrant {
  id String @id @default(cuid())

  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id], onDelete: Cascade)

  customerId String
  customer   User   @relation(fields: [customerId], references: [id], onDelete: Cascade)

  earnedSaleId String? @unique
  earnedSale   Sale?   @relation(fields: [earnedSaleId], references: [id], onDelete: SetNull)

  pointsGranted   Int
  pointsRemaining Int
  expiresAt DateTime

  createdAt DateTime @default(now())

  usages LoyaltyPointUsage[]

  @@index([shopId, customerId, expiresAt])
  @@index([customerId, expiresAt])
  @@map("loyalty_point_grants")
}

model LoyaltyPointUsage {
  id String @id @default(cuid())

  grantId String
  grant   LoyaltyPointGrant @relation(fields: [grantId], references: [id], onDelete: Cascade)

  saleId String
  sale   Sale @relation(fields: [saleId], references: [id], onDelete: Cascade)

  pointsUsed Int

  createdAt DateTime @default(now())

  @@index([saleId])
  @@index([grantId])
  @@map("loyalty_point_usages")
}

model PasswordResetToken {
  id String @id @default(cuid())

  userId String
  user   User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  tokenHash String @unique
  expiresAt DateTime
  usedAt DateTime?

  createdAt DateTime @default(now())

  @@index([userId, expiresAt])
  @@map("password_reset_tokens")
}

model LoyaltySettings {
  id     String @id @default(cuid())
  shopId String @unique
  shop   Shop   @relation(fields: [shopId], references: [id])

  minOrderFirstPoint Int
  minOrderApplyPoint Int
  validityMonths     Int
  maxEarnablePoints  Int
  maxRedeemPercent   Int

  earnType LoyaltyEarnType
  percentageRate Float?
  stepAmount Int?
  pointsPerStep Int?

  welcomeBonus Int
  referralBonus Int

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("loyalty_settings")
}

model LoyaltyProgram {
  id     String @id @default(cuid())
  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id])

  name String
  type LoyaltyProgramType
  isActive Boolean @default(true)

  // PERCENTAGE: percentageRate (0-100)
  percentageRate Float?
  // INCREMENTAL: earn pointsPerStep for every stepAmount spent
  stepAmount Int?
  pointsPerStep Int?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@map("loyalty_programs")
}

model DesignTemplate {
  id     String @id @default(cuid())
  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id])

  name  String
  scope DesignTemplateScope @default(ANY)
  design Json

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@map("design_templates")
}

model Coupon {
  id     String @id @default(cuid())
  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id])

  title            String
  shortDescription String?
  longDescription  String?

  /// Cashi coins needed to claim this coupon in Rewards marketplace.
  cashiCoinsCost Int @default(0) @map("cashi_coins_cost")

  valueType    CouponValueType
  valueFixed   Int?
  valuePercent Float?

  minOrderValue Int?
  totalCoupons  Int?
  distributionBid Int?

  status    CouponStatus @default(DRAFT)
  moderationStatus ModerationStatus @default(DRAFT)
  submittedAt DateTime?
  publishedAt DateTime?
  rejectedAt DateTime?
  rejectedReason String?
  activeAt  DateTime?
  expiresAt DateTime?

  imageUrl String?
  design   Json?

  /// Number of times coupon was resubmitted after rejection.
  resubmissionCount Int @default(0)

  issuedCount   Int @default(0)
  redeemedCount Int @default(0)

  assignments CustomerCoupon[]
  appliedSales Sale[] @relation("SaleAppliedCoupon")

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@index([moderationStatus, createdAt])
  @@map("coupons")
}

enum CustomerCouponStatus {
  ASSIGNED
  REDEEMED
  EXPIRED
}

model CustomerCoupon {
  id String @id @default(cuid())

  couponId String
  coupon Coupon @relation(fields: [couponId], references: [id], onDelete: Cascade)

  customerId String
  customer User @relation(fields: [customerId], references: [id], onDelete: Cascade)

  status CustomerCouponStatus @default(ASSIGNED)
  assignedAt DateTime @default(now())
  redeemedAt DateTime?
  /// Coins spent by the customer to claim this coupon (0 for free/distributed coupons).
  cashiCoinsSpent Int @default(0) @map("cashi_coins_spent")

  redeemedSaleId String?
  redeemedSale Sale? @relation("RedeemedSale", fields: [redeemedSaleId], references: [id], onDelete: SetNull)

  @@unique([customerId, couponId])
  @@index([couponId, status])
  @@index([customerId, status])
  @@map("customer_coupons")
}

model LuckyDraw {
  id     String @id @default(cuid())
  shopId String
  shop   Shop   @relation(fields: [shopId], references: [id])

  name        String
  description String?
  prize       String?

  status    LuckyDrawStatus @default(DRAFT)
  moderationStatus ModerationStatus @default(DRAFT)
  submittedAt DateTime?
  publishedAt DateTime?
  rejectedAt DateTime?
  rejectedReason String?
  startDate DateTime
  endDate   DateTime

  imageUrl String?
  design   Json?

  participantsCount Int @default(0)

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([shopId, createdAt])
  @@index([moderationStatus, createdAt])
  @@map("lucky_draws")
}

model Plan {
  id       String   @id @default(cuid())
  code     String @unique
  name     String
  priceMonthly Int    @default(0)
  currency     String @default("INR")
  features Json
  isActive Boolean @default(true)

  adminSubscriptions AdminSubscription[]

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("plans")
}

model OtpCode {
  id        String    @id @default(cuid())
  phone     String
  codeHash  String
  expiresAt DateTime
  consumedAt DateTime?
  createdAt DateTime  @default(now())

  @@index([phone, createdAt])
  @@map("otp_codes")
}

