generator client {
  provider     = "prisma-client"
  output       = "../generated/prisma"
  moduleFormat = "esm"
}

datasource db {
  provider = "mysql"
}

enum UserRole {
  USER
  ADMIN
}

enum UserStatus {
  ACTIVE
  SUSPENDED
}

enum AuthTokenType {
  EMAIL_VERIFY
  PASSWORD_RESET
}

enum CustomFieldType {
  TEXT
  NUMBER
  SELECT
  MULTISELECT
}

enum PhotoKind {
  GALLERY
  STATUS
}

enum PhotoStatus {
  PENDING
  APPROVED
  REJECTED
}

enum NotificationType {
  LIKE
  MESSAGE
  TAG
  QUOTE_RECEIVED
  COMMENT
  QUOTE_COMMENT
}

enum ConfessionVisibility {
  GIZLI
  ACIK
}

enum ConfessionAccess {
  MEMBERS_ONLY
  EVERYONE
}

enum QuoteSource {
  ADMIN
  BOT
}

enum ConfessionSource {
  USER
  BOT
}

enum BotTaskType {
  CONFESSION
  QUOTE
  ROOM_ARTICLE
  /// Gemini çağırmaz — her aktif kategoriden bekleyen (isActive=false) en eski sözü seçip yayına alır.
  QUOTE_DAILY_ROTATION
}

enum BotJobStatus {
  SUCCESS
  FAILED
}

model User {
  id              String     @id @default(cuid())
  email           String     @unique
  emailVerifiedAt DateTime?
  passwordHash    String
  role            UserRole   @default(USER)
  status          UserStatus @default(ACTIVE)
  createdAt       DateTime   @default(now())
  updatedAt       DateTime   @updatedAt

  profile           Profile?
  sessions          Session[]
  authTokens        AuthToken[]
  customFieldValues CustomFieldValue[]
  photos            Photo[]           @relation("PhotoOwner")
  moderatedPhotos   Photo[]           @relation("PhotoModerator")
  taggedInPhotos    Photo[]           @relation("PhotoTaggedUser")
  likesGiven        Like[]            @relation("LikeFrom")
  likesReceived     Like[]            @relation("LikeTo")
  notifications     Notification[]
  usageCounters     UsageCounter[]
  conversationsAsA  Conversation[]    @relation("ConversationA")
  conversationsAsB  Conversation[]    @relation("ConversationB")
  messages          Message[]
  confessions       Confession[]
  confessionTags    ConfessionTag[]
  confessionLikes   ConfessionLike[]
  confessionComments ConfessionComment[]
  quoteSendsFrom    QuoteSend[]       @relation("QuoteSendFrom")
  quoteSendsTo      QuoteSend[]       @relation("QuoteSendTo")
  quoteLikes        QuoteLike[]
  quoteComments     QuoteComment[]

  @@map("users")
}

model Session {
  id        String   @id @default(cuid())
  userId    String
  tokenHash String   @unique
  userAgent String?  @db.Text
  ip        String?
  expiresAt DateTime
  createdAt DateTime @default(now())

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

  @@index([userId])
  @@map("sessions")
}

model AuthToken {
  id        String        @id @default(cuid())
  userId    String
  type      AuthTokenType
  tokenHash String        @unique
  expiresAt DateTime
  usedAt    DateTime?
  createdAt DateTime      @default(now())

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

  @@index([userId, type])
  @@map("auth_tokens")
}

model Profile {
  id            String   @id @default(cuid())
  userId        String   @unique
  username      String   @unique
  fullName      String
  phone         String?
  address       String?  @db.Text
  city          String?
  age           Int?
  hobbies       String?  @db.Text
  phobias       String?  @db.Text
  cinemaTaste   String?  @db.Text
  musicTaste    String?  @db.Text
  bio           String?  @db.Text
  avatarPhotoId String?  @unique
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  user        User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  avatarPhoto Photo? @relation("ProfileAvatar", fields: [avatarPhotoId], references: [id], onDelete: SetNull)

  @@map("profiles")
}

/// Admin panelden kod değişikliği olmadan yeni profil alanları eklenebilmesi için (EAV deseni).
model CustomFieldDefinition {
  id        String          @id @default(cuid())
  key       String          @unique
  label     String
  fieldType CustomFieldType @default(TEXT)
  options   Json?
  isActive  Boolean         @default(true)
  sortOrder Int             @default(0)
  createdAt DateTime        @default(now())

  values CustomFieldValue[]

  @@map("custom_field_definitions")
}

model CustomFieldValue {
  id                String   @id @default(cuid())
  userId            String
  fieldDefinitionId String
  value             String   @db.Text
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt

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

  @@unique([userId, fieldDefinitionId])
  @@map("custom_field_values")
}

model Photo {
  id           String      @id @default(cuid())
  userId       String
  url          String
  thumbUrl     String
  altText      String?
  kind         PhotoKind   @default(GALLERY)
  status       PhotoStatus @default(PENDING)
  expiresAt    DateTime?
  sortOrder    Int         @default(0)
  youtubeUrl   String?
  youtubeTitle String?
  taggedUserId String?
  moderatedById String?
  moderatedAt  DateTime?
  createdAt    DateTime    @default(now())

  user            User     @relation("PhotoOwner", fields: [userId], references: [id], onDelete: Cascade)
  moderatedBy     User?    @relation("PhotoModerator", fields: [moderatedById], references: [id], onDelete: SetNull)
  taggedUser      User?    @relation("PhotoTaggedUser", fields: [taggedUserId], references: [id], onDelete: SetNull)
  avatarOfProfile Profile? @relation("ProfileAvatar")

  @@index([userId, kind])
  @@index([status])
  @@map("photos")
}

model Like {
  id         String   @id @default(cuid())
  fromUserId String
  toUserId   String
  createdAt  DateTime @default(now())

  fromUser User @relation("LikeFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
  toUser   User @relation("LikeTo", fields: [toUserId], references: [id], onDelete: Cascade)

  @@unique([fromUserId, toUserId])
  @@map("likes")
}

model Notification {
  id        String           @id @default(cuid())
  userId    String
  type      NotificationType
  payload   Json
  isRead    Boolean          @default(false)
  createdAt DateTime         @default(now())

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

  @@index([userId, isRead])
  @@map("notifications")
}

/// Admin panelden düzenlenebilir limitler (örn. "photo_uploads_per_period").
model RateLimitSetting {
  key         String   @id
  limitValue  Int
  periodHours Int
  updatedAt   DateTime @updatedAt

  @@map("rate_limit_settings")
}

/// RateLimitSetting'e karşı atomik sayaç — periodStart, periyodun başlangıç zaman damgasıdır.
model UsageCounter {
  id          String   @id @default(cuid())
  userId      String
  counterKey  String
  periodStart DateTime
  count       Int      @default(0)

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

  @@unique([userId, counterKey, periodStart])
  @@map("usage_counters")
}

/// userAId her zaman userBId'den küçüktür (lib/messages/conversation.ts normalize eder) —
/// bu sayede kim başlatırsa başlatsın aynı ikili için tek konuşma satırı garanti edilir.
model Conversation {
  id            String    @id @default(cuid())
  userAId       String
  userBId       String
  lastMessageAt DateTime?
  createdAt     DateTime  @default(now())

  userA    User      @relation("ConversationA", fields: [userAId], references: [id], onDelete: Cascade)
  userB    User      @relation("ConversationB", fields: [userBId], references: [id], onDelete: Cascade)
  messages Message[]

  @@unique([userAId, userBId])
  @@map("conversations")
}

model Message {
  id             String   @id @default(cuid())
  conversationId String
  senderId       String
  body           String   @db.Text
  isRead         Boolean  @default(false)
  createdAt      DateTime @default(now())

  conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
  sender       User         @relation(fields: [senderId], references: [id], onDelete: Cascade)

  @@index([conversationId, createdAt])
  @@map("messages")
}

model Confession {
  id         String               @id @default(cuid())
  userId     String
  title      String
  slug       String               @unique
  body       String               @db.Text
  visibility ConfessionVisibility @default(ACIK)
  source     ConfessionSource     @default(USER)
  isActive   Boolean              @default(true)
  sortOrder  Int                  @default(0)
  viewCount  Int                  @default(0)
  createdAt  DateTime             @default(now())

  user     User                 @relation(fields: [userId], references: [id], onDelete: Cascade)
  tags     ConfessionTag[]
  likes    ConfessionLike[]
  comments ConfessionComment[]

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

/// İtiraf yorumları — yoruma cevap ve alıntı, parentId ile tek seviyeli dallanma sağlar:
/// bir cevap hem üst yoruma (thread) hem de doğrudan hangi yorumu yanıtladığına (alıntı) işaret eder.
model ConfessionComment {
  id           String   @id @default(cuid())
  confessionId String
  userId       String
  parentId     String?
  body         String   @db.Text
  isActive     Boolean  @default(true)
  createdAt    DateTime @default(now())

  confession Confession          @relation(fields: [confessionId], references: [id], onDelete: Cascade)
  user       User                @relation(fields: [userId], references: [id], onDelete: Cascade)
  parent     ConfessionComment?  @relation("CommentReplies", fields: [parentId], references: [id], onDelete: Cascade)
  replies    ConfessionComment[] @relation("CommentReplies")

  @@index([confessionId, createdAt])
  @@map("confession_comments")
}

model ConfessionLike {
  id           String   @id @default(cuid())
  confessionId String
  userId       String
  createdAt    DateTime @default(now())

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

  @@unique([confessionId, userId])
  @@map("confession_likes")
}

model ConfessionTag {
  id            String   @id @default(cuid())
  confessionId  String
  taggedUserId  String
  createdAt     DateTime @default(now())

  confession Confession @relation(fields: [confessionId], references: [id], onDelete: Cascade)
  taggedUser User       @relation(fields: [taggedUserId], references: [id], onDelete: Cascade)

  @@map("confession_tags")
}

model QuoteCategory {
  id        String   @id @default(cuid())
  name      String
  slug      String   @unique
  isActive  Boolean  @default(true)
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())

  quotes       Quote[]
  botSchedules BotSchedule[]

  @@map("quote_categories")
}

model Quote {
  id         String      @id @default(cuid())
  text       String      @db.Text
  author     String?
  slug       String      @unique
  categoryId String
  source     QuoteSource @default(ADMIN)
  isActive   Boolean     @default(true)
  sortOrder  Int         @default(0)
  viewCount  Int         @default(0)
  createdAt  DateTime    @default(now())

  category QuoteCategory  @relation(fields: [categoryId], references: [id], onDelete: Cascade)
  sends    QuoteSend[]
  likes    QuoteLike[]
  comments QuoteComment[]

  @@index([categoryId, isActive])
  @@map("quotes")
}

model QuoteLike {
  id        String   @id @default(cuid())
  quoteId   String
  userId    String
  createdAt DateTime @default(now())

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

  @@unique([quoteId, userId])
  @@map("quote_likes")
}

model QuoteComment {
  id        String   @id @default(cuid())
  quoteId   String
  userId    String
  parentId  String?
  body      String   @db.Text
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())

  quote   Quote          @relation(fields: [quoteId], references: [id], onDelete: Cascade)
  user    User           @relation(fields: [userId], references: [id], onDelete: Cascade)
  parent  QuoteComment?  @relation("QuoteCommentReplies", fields: [parentId], references: [id], onDelete: Cascade)
  replies QuoteComment[] @relation("QuoteCommentReplies")

  @@index([quoteId, createdAt])
  @@map("quote_comments")
}

model QuoteSend {
  id         String   @id @default(cuid())
  quoteId    String
  fromUserId String
  toUserId   String
  createdAt  DateTime @default(now())

  quote    Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
  fromUser User  @relation("QuoteSendFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
  toUser   User  @relation("QuoteSendTo", fields: [toUserId], references: [id], onDelete: Cascade)

  @@map("quote_sends")
}

model RoomCategory {
  id        String   @id @default(cuid())
  name      String
  slug      String   @unique
  isActive  Boolean  @default(true)
  sortOrder Int      @default(0)
  createdAt DateTime @default(now())

  rooms Room[]

  @@map("room_categories")
}

/// Faz 5: "Odalar" — botun/adminin yazdığı tanıtım makalesiyle sunulan içerik/dizin sayfaları.
model Room {
  id           String   @id @default(cuid())
  name         String
  slug         String   @unique
  description  String?  @db.Text
  introArticle String?  @db.Text
  coverImage   String?
  categoryId   String
  isActive     Boolean  @default(true)
  sortOrder    Int      @default(0)
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  category     RoomCategory  @relation(fields: [categoryId], references: [id])
  botSchedules BotSchedule[]

  @@index([categoryId, isActive])
  @@map("rooms")
}

/// Admin tanımlı, gün/saat bazlı Gemini içerik üretim zamanlaması.
model BotSchedule {
  id          String      @id @default(cuid())
  taskType    BotTaskType
  runDays     String
  runTime     String
  categoryId  String?
  roomId      String?
  autoPublish Boolean     @default(false)
  isActive    Boolean     @default(true)
  lastRunAt   DateTime?
  createdAt   DateTime    @default(now())
  updatedAt   DateTime    @updatedAt

  category QuoteCategory? @relation(fields: [categoryId], references: [id], onDelete: Cascade)
  room     Room?          @relation(fields: [roomId], references: [id], onDelete: Cascade)
  jobLogs  BotJobLog[]

  @@index([isActive])
  @@map("bot_schedules")
}

model BotJobLog {
  id             String       @id @default(cuid())
  scheduleId     String
  runAt          DateTime     @default(now())
  status         BotJobStatus
  generatedCount Int          @default(0)
  errorMessage   String?      @db.Text
  rawResponse    Json?

  schedule BotSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)

  @@index([scheduleId, runAt])
  @@map("bot_job_logs")
}

/// Tekil satır (id sabit "default").
model SiteSetting {
  id                    String           @id @default("default")
  confessionVisibility  ConfessionAccess @default(EVERYONE)

  // Faz 6: SEO / genel site kimliği
  siteTitle             String           @default("SohbeteGir.com")
  siteDescription       String?          @db.Text
  logoUrl               String?
  faviconUrl            String?
  defaultOgImage        String?
  organizationName      String           @default("SohbeteGir")
  organizationLegalName String?
  indexNowKey           String?

  // Faz 7: duyuru barı + iletişim formu bildirim e-postası
  announcementText   String?  @db.Text
  announcementActive Boolean  @default(false)
  contactEmail       String?

  // E-posta doğrulama zorunluluğu — admin panelinden açılıp kapatılabilir (bkz. admin/ayarlar).
  // Kapalıyken kayıt olan üye e-posta doğrulaması beklenmeden doğrudan oturum açar.
  requireEmailVerification Boolean @default(true)

  // Faz 7: Google Analytics / Search Console entegrasyonu
  gaMeasurementId           String?
  searchConsoleVerification String?

  // İçerik botu (Gemini) API anahtarı — admin panelinden girilir, tanımlı değilse bot-worker .env.local'e düşer
  geminiApiKey String?

  // Faz 8: sitemap.xml bölüm anahtarları + robots.txt kuralları — admin panelinden yönetilir
  sitemapIncludeStatic          Boolean @default(true)
  sitemapIncludeProfiles        Boolean @default(true)
  sitemapIncludeRooms           Boolean @default(true)
  sitemapIncludeRoomCategories  Boolean @default(true)
  sitemapIncludeQuotes          Boolean @default(true)
  sitemapIncludeQuoteCategories Boolean @default(true)
  sitemapIncludeConfessions     Boolean @default(true)
  robotsDisallowPaths           String? @db.Text

  updatedAt DateTime @updatedAt

  @@map("site_settings")
}

enum HomeSectionKey {
  ISTATISTIK
  UYELER
  ITIRAFLAR
  SOZLER
  ODALAR
  OZELLIKLER
  ADIMLAR
}

/// Ana sayfadaki (hero ve son CTA dışındaki) bölümlerin admin panelinden aktif/pasif +
/// sürükle-bırak sıralaması. Her key için tek satır — ilk okumada eksikse varsayılanlarla seed edilir.
model HomeSection {
  id        String         @id @default(cuid())
  key       HomeSectionKey @unique
  isActive  Boolean        @default(true)
  sortOrder Int            @default(0)
  updatedAt DateTime       @updatedAt

  @@map("home_sections")
}

/// Herkese açık iletişim formundan gelen mesajlar — admin panelinden görüntülenir.
model ContactMessage {
  id        String   @id @default(cuid())
  name      String
  email     String
  subject   String
  body      String   @db.Text
  isRead    Boolean  @default(false)
  createdAt DateTime @default(now())

  @@map("contact_messages")
}

/// "Listelenecek içerik sayısı" — bölüm başına admin panelden ayarlanabilir (örn. "itiraflar_listesi" -> 20).
model DisplaySetting {
  sectionKey String @id
  itemCount  Int

  @@map("display_settings")
}

/// Statik sayfa bazlı SEO override'ları (path -> özel başlık/açıklama/OG görsel).
model SeoMeta {
  path               String  @id
  title              String?
  metaDescription    String? @db.Text
  ogImage            String?
  robots             String  @default("index,follow")
  schemaJsonOverride Json?
  updatedAt          DateTime @updatedAt

  @@map("seo_meta")
}
