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

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

model User {
  id               String    @id @default(cuid())
  email            String    @unique
  passwordHash     String
  name             String?
  activeAccountId  String?
  createdAt        DateTime  @default(now())
  updatedAt        DateTime  @updatedAt
  accounts         Account[]
  sessions         Session[]
  settings         Setting?
}

model Session {
  id        String   @id @default(cuid())
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  token     String   @unique
  expiresAt DateTime
  createdAt DateTime @default(now())
}

model Account {
  id                    String   @id @default(cuid())
  userId                String?
  user                  User?    @relation(fields: [userId], references: [id], onDelete: Cascade)
  username              String?
  displayName           String?
  persona               String?
  styleProfile          String?
  styleBenchmark        String?
  brief                 String?
  productBrief          String?
  targetAudience        String?
  goals                 String?
  storageState          String   @default("")
  valid                 Boolean  @default(true)
  threadsAccessToken    String?
  threadsUserId         String?
  threadsTokenExpiresAt DateTime?
  automationEnabled     Boolean  @default(false)
  searchViaApi          Boolean  @default(false)
  /// mixed | threads | brave | crawler | threads_brave | threads_crawler | brave_crawler
  searchSourceMode      String   @default("mixed")
  publishViaApi         Boolean  @default(false)
  devMode               Boolean  @default(true)
  scrapeReplies         Boolean  @default(true)
  repliesPerPost        Int      @default(10)
  publishHeaded         Boolean  @default(false)
  playwrightDebug       Boolean  @default(false)
  createdAt             DateTime @default(now())
  updatedAt             DateTime @updatedAt
  automationRules       AutomationRule[]
}

/// 每帳號 × 每任務的自動化規則：mode=manual 先審核，mode=auto 自動執行（受 dailyCap 與排程限制）
model AutomationRule {
  id        String   @id @default(cuid())
  accountId String
  account   Account  @relation(fields: [accountId], references: [id], onDelete: Cascade)
  taskType  String   // scan | generate | outreach | engagement | publish
  mode      String   @default("manual") // manual | auto
  dailyCap  Int      @default(20)
  schedule  String   @default("0 9 * * *")
  enabled   Boolean  @default(false)
  lastRunAt DateTime?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@unique([accountId, taskType])
}

/// 自動化動作稽核紀錄，供成效回溯與「殺停」後檢視
model ActionLog {
  id         String   @id @default(cuid())
  accountId  String?
  taskType   String   // scan | generate | outreach | engagement | publish
  action     String   // publish-post | reply-outreach | reply-inbound | scan | generate
  mode       String   @default("auto") // auto | manual
  status     String   @default("success") // success | failed | skipped
  targetId   String?
  externalId String?
  permalink  String?
  detail     String?
  error      String?
  createdAt  DateTime @default(now())
}

model BrandProfile {
  id        String           @id @default(cuid())
  accountId String?
  name      String
  notes     String?
  createdAt DateTime         @default(now())
  updatedAt DateTime         @updatedAt
  products  ProductProfile[]
  topics    Topic[]
}

model ProductProfile {
  id        String        @id @default(cuid())
  accountId String?
  brandId   String?
  brand     BrandProfile? @relation(fields: [brandId], references: [id], onDelete: Cascade)
  label     String
  context   String        @default("")
  matchTags String?
  createdAt DateTime      @default(now())
  updatedAt DateTime      @updatedAt
  topics    Topic[]
}

model Topic {
  id               String          @id @default(cuid())
  accountId        String?
  label            String
  query            String
  brief            String?
  productContext   String?
  brandProfileId   String?
  brandProfile     BrandProfile?   @relation(fields: [brandProfileId], references: [id], onDelete: SetNull)
  productProfileId String?
  productProfile   ProductProfile? @relation(fields: [productProfileId], references: [id], onDelete: SetNull)
  topicGoal        String          @default("viral")
  researchMap      String?
  selectedTags     String?
  active           Boolean         @default(true)
  createdAt        DateTime        @default(now())
  scans            Scan[]
}

model Scan {
  id        String     @id @default(cuid())
  accountId String?
  topicId   String
  topic     Topic      @relation(fields: [topicId], references: [id], onDelete: Cascade)
  scanMode  String     @default("single")
  scanGoal  String     @default("viral")
  scanTags  String?
  searchSource   String?  // api | browser | web | hybrid：這次海巡實際用哪種方式找到貼文
  repliesFetched Boolean  @default(false) // 是否有抓到別人貼文的留言（需瀏覽器）
  repliesCount   Int      @default(0)     // 抓到的留言則數
  createdAt DateTime   @default(now())
  items     ScanItem[]
}

model ScanItem {
  id              String    @id @default(cuid())
  scanId          String
  scan            Scan      @relation(fields: [scanId], references: [id], onDelete: Cascade)
  externalId      String?
  text            String
  permalink       String?
  authorName      String?
  postedAt        DateTime?
  likeCount       Int?
  replyCount      Int?
  score           Float
  searchTag       String?
  relevanceScore  Float?
  placementScore  Float?
  placementReason String?
  qualityTier     String?
  qualityReason   String?
  combinedScore   Float?
  mediaUrls       String?
  mediaType       String?
  viralAnalysis   String?
  replies         Reply[]
  outreachTargets OutreachTarget[]
}

model Reply {
  id         String    @id @default(cuid())
  scanItemId String
  scanItem   ScanItem  @relation(fields: [scanItemId], references: [id], onDelete: Cascade)
  text       String
  authorName String?
  likeCount  Int?
  postedAt   DateTime?
}

model Draft {
  id             String   @id @default(cuid())
  accountId      String?
  topicId        String?
  text           String
  angle          String?
  rationale      String?
  hook           String?
  referenceNotes String?
  searchTag      String?
  sortOrder      Int?
  sources        String?
  draftType      String?
  imageBrief     String?
  imagePath      String?
  imagePaths     String?
  scanItemId     String?
  status         String   @default("PENDING")
  factCheckResult String?
  createdAt      DateTime @default(now())
}

model Published {
  id          String   @id @default(cuid())
  accountId   String?
  topicId     String?
  externalId  String?
  text        String
  angle       String?
  hook        String?
  rationale   String?
  draftType   String?
  permalink   String?
  publishedAt DateTime @default(now())
  views       Int?
  likes       Int?
  replies     Int?
  reposts     Int?
  quotes      Int?
  snapshots   PerformanceSnapshot[]
  inboundReplies InboundReply[]
}

model PerformanceSnapshot {
  id          String    @id @default(cuid())
  publishedId String?
  published   Published? @relation(fields: [publishedId], references: [id], onDelete: Cascade)
  profileId   String?
  views       Int?
  likes       Int?
  replies     Int?
  reposts     Int?
  quotes      Int?
  followers   Int?
  source      String    @default("threads-api")
  capturedAt  DateTime  @default(now())
}

model InboundReply {
  id          String   @id @default(cuid())
  publishedId String?
  published   Published? @relation(fields: [publishedId], references: [id], onDelete: Cascade)
  externalId  String?  @unique
  parentId    String?
  text        String
  authorName  String?
  permalink   String?
  postedAt    DateTime?
  likeCount   Int?
  sentiment   String?
  intent      String?
  status      String   @default("NEW")
  createdAt   DateTime @default(now())
  replyDrafts ReplyDraft[]
}

model ReplyDraft {
  id             String       @id @default(cuid())
  inboundReplyId String
  inboundReply   InboundReply @relation(fields: [inboundReplyId], references: [id], onDelete: Cascade)
  text           String
  rationale      String?
  status         String       @default("PENDING")
  createdAt      DateTime     @default(now())
  publishedAt    DateTime?
}

model OutreachTarget {
  id          String    @id @default(cuid())
  scanItemId  String
  scanItem    ScanItem  @relation(fields: [scanItemId], references: [id], onDelete: Cascade)
  status      String    @default("NEW")
  relevance   Float?
  reason      String?
  createdAt   DateTime  @default(now())
  drafts      OutreachDraft[]
}

model OutreachDraft {
  id               String         @id @default(cuid())
  outreachTargetId String
  outreachTarget   OutreachTarget @relation(fields: [outreachTargetId], references: [id], onDelete: Cascade)
  text             String
  angle            String?
  rationale        String?
  status           String         @default("PENDING")
  createdAt        DateTime       @default(now())
  publishedAt      DateTime?
}

model BackgroundJob {
  id          String    @id @default(cuid())
  accountId   String?
  type        String
  status      String    @default("pending")
  topicId     String?
  label       String?
  payload     String?
  result      String?
  error       String?
  progress       String?
  progressDetail String?
  createdAt      DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  completedAt DateTime?
}

model Setting {
  id                   String   @id @default(cuid())
  userId               String?  @unique
  user                 User?    @relation(fields: [userId], references: [id], onDelete: Cascade)
  persona              String?
  aiProvider           String   @default("xai")
  aiModel              String   @default("grok-3")
  researchAiProvider   String?
  researchAiModel      String?
  draftsPerScan        Int      @default(4)
  matrixRows           Int      @default(7)
  scanCron             String   @default("0 9 * * *")
  scrapeReplies        Boolean  @default(true)
  repliesPerPost       Int      @default(10)
  playwrightDebug      Boolean  @default(false)
  providerApiKeys      String?
  threadsAppId         String?
  threadsAppSecret     String?
  appUrl               String?
  publishViaApi        Boolean  @default(true)
  searchViaApi         Boolean  @default(true)
  publishHeaded        Boolean  @default(true)
  devMode              Boolean  @default(false)
  connectionMigrated   Boolean  @default(false)
}
