// Dimension47 - TTRPG Campaign Management Platform
// Prisma Schema

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

datasource db {
  provider = "postgresql"
}

// ==========================================
// ENUMS
// ==========================================

enum UserRole {
  ADMIN
  GM
  PLAYER
}

enum CharacterType {
  PC
  NPC
}

enum AbilityType {
  STR
  DEX
  CON
  INT
  WIS
  CHA
}

enum Proficiency {
  UNTRAINED
  TRAINED
  EXPERT
  MASTER
  LEGENDARY
}

enum FeatSource {
  CLASS
  ANCESTRY
  GENERAL
  SKILL
  BONUS
  ARCHETYPE
}

enum SpellTradition {
  ARCANE
  DIVINE
  OCCULT
  PRIMAL
}

enum CombatantType {
  PC
  NPC
  MONSTER
}

enum ActionType {
  ACTION
  REACTION
  FREE
}

enum HighlightColor {
  YELLOW
  GREEN
  BLUE
  PINK
}

enum TranslationType {
  FEAT
  EQUIPMENT
  SPELL
  TRAIT
  ANCESTRY
  HERITAGE
  CLASS
  BACKGROUND
  CONDITION
  ACTION
}

enum TranslationQuality {
  HIGH
  MEDIUM
  LOW
}

enum ResearchField {
  BOMBER
  CHIRURGEON
  MUTAGENIST
  TOXICOLOGIST
}

// ==========================================
// USER & AUTH
// ==========================================

model User {
  id            String   @id @default(uuid())
  username      String   @unique
  email         String   @unique
  passwordHash  String
  role          UserRole @default(PLAYER)
  avatarUrl     String?
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  // Relations
  gmCampaigns       Campaign[]        @relation("CampaignGM")
  campaignMembers   CampaignMember[]
  characters        Character[]       @relation("CharacterOwner")
  uploadedDocuments Document[]
  documentAccess    DocumentAccess[]
  highlights        Highlight[]
  notes             Note[]
  noteShares        NoteShare[]
}

// ==========================================
// CAMPAIGNS
// ==========================================

model Campaign {
  id          String   @id @default(uuid())
  name        String
  description String?
  gmId        String
  imageUrl    String?
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  // Relations
  gm              User              @relation("CampaignGM", fields: [gmId], references: [id])
  members         CampaignMember[]
  characters      Character[]
  battleMaps      BattleMap[]
  combatants      Combatant[]
  battleSessions  BattleSession[]
  documents       Document[]
  notes           Note[]
}

model CampaignMember {
  campaignId String
  userId     String
  joinedAt   DateTime @default(now())

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

  @@id([campaignId, userId])
}

// ==========================================
// CHARACTERS (Normalisiert)
// ==========================================

model Character {
  id          String        @id @default(uuid())
  campaignId  String
  ownerId     String?
  name        String
  type        CharacterType @default(PC)
  level       Int           @default(1)
  avatarUrl   String?

  // Core Stats
  hpCurrent   Int
  hpMax       Int
  hpTemp      Int           @default(0)

  // Ancestry/Class/Background (References)
  ancestryId    String?
  heritageId    String?
  classId       String?
  backgroundId  String?

  // Experience
  experiencePoints Int @default(0)

  // Currency (Ironvale uses Credits instead of Gold/Silver/Copper)
  credits Int @default(0)

  // Pathbuilder Import Data (JSON blob for original import)
  pathbuilderData Json?

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

  // Relations
  campaign    Campaign             @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  owner       User?                @relation("CharacterOwner", fields: [ownerId], references: [id])
  abilities   CharacterAbility[]
  feats       CharacterFeat[]
  skills      CharacterSkill[]
  spells      CharacterSpell[]
  items       CharacterItem[]
  conditions  CharacterCondition[]
  resources   CharacterResource[]
  battleTokens BattleToken[]
  documentAccess DocumentAccess[]

  // Alchemy
  alchemyState   CharacterAlchemyState?
  formulas       CharacterFormula[]
  preparedItems  CharacterPreparedItem[]
}

model CharacterAbility {
  id          String      @id @default(uuid())
  characterId String
  ability     AbilityType
  score       Int

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)

  @@unique([characterId, ability])
}

model CharacterFeat {
  id          String     @id @default(uuid())
  characterId String
  featId      String?    // Reference to Feat table
  name        String     // English name
  nameGerman  String?    // German translation
  level       Int        // Level obtained
  source      FeatSource

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
  feat      Feat?     @relation(fields: [featId], references: [id])
}

model CharacterSkill {
  id          String      @id @default(uuid())
  characterId String
  skillName   String
  proficiency Proficiency @default(UNTRAINED)

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)

  @@unique([characterId, skillName])
}

model CharacterSpell {
  id          String         @id @default(uuid())
  characterId String
  spellId     String?
  name        String
  nameGerman  String?
  tradition   SpellTradition
  spellLevel  Int
  prepared    Boolean        @default(false)

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
  spell     Spell?    @relation(fields: [spellId], references: [id])
}

model CharacterItem {
  id          String  @id @default(uuid())
  characterId String
  equipmentId String? // Reference to Equipment library
  name        String
  nameGerman  String?
  quantity    Int     @default(1)
  bulk        Decimal @default(0)
  equipped    Boolean @default(false)
  invested    Boolean @default(false)
  containerId String? // For containers
  notes       String?

  // Player-editable: Alias/Nickname for the item
  alias       String?

  // GM-editable: Custom overrides for item properties
  customName       String?   // Override display name
  customDamage     String?   // Override damage dice (e.g. "2d6")
  customDamageType String?   // Override damage type (e.g. "fire")
  customTraits     String[]  // Override/add traits
  customRange      String?   // Override range
  customHands      String?   // Override hands requirement

  character Character  @relation(fields: [characterId], references: [id], onDelete: Cascade)
  equipment Equipment? @relation(fields: [equipmentId], references: [id])
}

model CharacterCondition {
  id          String @id @default(uuid())
  characterId String
  name        String
  nameGerman  String?
  value       Int?   // For valued conditions like Frightened 2
  duration    String?
  source      String?

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
}

model CharacterResource {
  id          String @id @default(uuid())
  characterId String
  name        String
  current     Int
  max         Int

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)

  @@unique([characterId, name])
}

// ==========================================
// ALCHEMY SYSTEM
// ==========================================

model CharacterAlchemyState {
  id                      String         @id @default(uuid())
  characterId             String         @unique
  researchField           ResearchField?
  versatileVialsCurrent   Int            @default(0)
  versatileVialsMax       Int            @default(0)
  advancedAlchemyBatch    Int            @default(0)
  advancedAlchemyMax      Int            @default(0)
  lastRestAt              DateTime?

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
}

model CharacterFormula {
  id            String  @id @default(uuid())
  characterId   String
  equipmentId   String
  name          String
  nameGerman    String?
  learnedAt     Int     @default(1)
  formulaSource String? // "Pathbuilder Import", "Purchased", "Found"

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
  equipment Equipment @relation(fields: [equipmentId], references: [id])

  @@unique([characterId, equipmentId])
  @@index([characterId])
}

model CharacterPreparedItem {
  id              String   @id @default(uuid())
  characterId     String
  equipmentId     String
  name            String
  nameGerman      String?
  quantity        Int      @default(1)
  isQuickAlchemy  Boolean  @default(false)
  isInfused       Boolean  @default(true)  // Infused items expire on rest, permanent items don't
  createdAt       DateTime @default(now())

  character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
  equipment Equipment @relation(fields: [equipmentId], references: [id])

  @@index([characterId])
}

// ==========================================
// BATTLE SYSTEM
// ==========================================

model BattleMap {
  id          String   @id @default(uuid())
  campaignId  String
  name        String
  imageUrl    String
  gridSizeX   Int      @default(20)
  gridSizeY   Int      @default(20)
  gridOffsetX Int      @default(0)
  gridOffsetY Int      @default(0)
  createdAt   DateTime @default(now())

  campaign       Campaign        @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  battleSessions BattleSession[]
}

model Combatant {
  id          String        @id @default(uuid())
  campaignId  String
  name        String
  type        CombatantType
  level       Int
  hpMax       Int
  ac          Int

  // Saves
  fortitude   Int
  reflex      Int
  will        Int
  perception  Int

  // Speed
  speed       Int @default(25)

  avatarUrl   String?
  description String?
  createdAt   DateTime @default(now())

  campaign      Campaign           @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  abilities     CombatantAbility[]
  battleTokens  BattleToken[]
}

model CombatantAbility {
  id          String     @id @default(uuid())
  combatantId String
  name        String
  actionCost  Int        // 1, 2, 3, or 0 for free/reaction
  actionType  ActionType
  description String
  damage      String?    // e.g. "2d6+4 slashing"
  traits      String[]

  combatant Combatant @relation(fields: [combatantId], references: [id], onDelete: Cascade)
}

model BattleSession {
  id          String   @id @default(uuid())
  campaignId  String
  mapId       String?
  name        String?
  isActive    Boolean  @default(false)
  roundNumber Int      @default(0)
  createdAt   DateTime @default(now())

  campaign Campaign   @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  map      BattleMap? @relation(fields: [mapId], references: [id])
  tokens   BattleToken[]
}

model BattleToken {
  id              String   @id @default(uuid())
  battleSessionId String
  combatantId     String?
  characterId     String?
  name            String
  positionX       Float
  positionY       Float
  hpCurrent       Int
  hpMax           Int
  initiative      Int?
  conditions      String[]
  size            Int      @default(1) // 1 = Medium, 2 = Large, etc.

  battleSession BattleSession @relation(fields: [battleSessionId], references: [id], onDelete: Cascade)
  combatant     Combatant?    @relation(fields: [combatantId], references: [id])
  character     Character?    @relation(fields: [characterId], references: [id])
}

// ==========================================
// DOCUMENTS SYSTEM
// ==========================================

model Document {
  id          String   @id @default(uuid())
  campaignId  String
  title       String
  description String?
  category    String?
  tags        String[]
  filePath    String
  fileType    String   // html, pdf
  uploadedBy  String
  createdAt   DateTime @default(now())

  campaign   Campaign         @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  uploader   User             @relation(fields: [uploadedBy], references: [id])
  access     DocumentAccess[]
  highlights Highlight[]
}

model DocumentAccess {
  id          String  @id @default(uuid())
  documentId  String
  userId      String?     // NULL = all campaign members
  characterId String?     // Access per character

  document  Document   @relation(fields: [documentId], references: [id], onDelete: Cascade)
  user      User?      @relation(fields: [userId], references: [id])
  character Character? @relation(fields: [characterId], references: [id])

  @@unique([documentId, userId, characterId])
}

model Highlight {
  id            String         @id @default(uuid())
  documentId    String
  userId        String
  selectionText String
  startOffset   Int
  endOffset     Int
  color         HighlightColor
  note          String?
  createdAt     DateTime       @default(now())

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

model Note {
  id          String   @id @default(uuid())
  userId      String
  campaignId  String
  title       String
  content     String   // Markdown
  isShared    Boolean  @default(false)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  user     User        @relation(fields: [userId], references: [id])
  campaign Campaign    @relation(fields: [campaignId], references: [id], onDelete: Cascade)
  shares   NoteShare[]
}

model NoteShare {
  noteId String
  userId String

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

  @@id([noteId, userId])
}

// ==========================================
// REFERENCE DATA (Pathfinder 2e)
// ==========================================

model Feat {
  id            String   @id @default(uuid())
  name          String   @unique
  traits        String[]
  summary       String?
  description   String?  // Full feat description/benefit text
  actions       String?  // "1", "2", "3", "free", "reaction", null for passive
  url           String?
  level         Int?     // Minimum level requirement
  sourceBook    String?

  // Feat classification
  featType      String?  // "General", "Skill", "Class", "Ancestry", "Archetype", "Heritage"
  rarity        String?  // "Common", "Uncommon", "Rare", "Unique"

  // Prerequisites
  prerequisites String?  // Text description of prerequisites

  // For class/archetype feats
  className     String?  // "Fighter", "Wizard", etc.
  archetypeName String?  // "Sentinel", "Medic", etc.

  // For ancestry feats
  ancestryName  String?  // "Human", "Elf", etc.

  // For skill feats
  skillName     String?  // "Acrobatics", "Athletics", etc.

  // Cached German translation
  nameGerman    String?
  summaryGerman String?

  characterFeats CharacterFeat[]

  @@index([featType])
  @@index([className])
  @@index([ancestryName])
  @@index([level])
}

model Equipment {
  id              String  @id @default(uuid())
  name            String  @unique
  traits          String[]
  itemCategory    String  // "Weapons", "Armor", "Consumables", "Shields", etc.
  itemSubcategory String?
  bulk            String? // "L" for light, "1", "2", etc.
  url             String?
  summary         String?
  level           Int?
  price           Int?    // In CP

  // Weapon-specific fields
  hands           String?
  damage          String? // "1d8 S", "1d6 P", etc.
  damageType      String? // "S", "P", "B" (Slashing, Piercing, Bludgeoning)
  range           String?
  reload          String?
  weaponCategory  String? // "Simple", "Martial", "Advanced", "Ammunition"
  weaponGroup     String? // "Sword", "Axe", "Bow", etc.

  // Armor-specific fields
  ac              Int?
  dexCap          Int?
  checkPenalty    Int?
  speedPenalty    Int?
  strength        Int?    // Strength requirement
  armorCategory   String? // "Unarmored", "Light", "Medium", "Heavy"
  armorGroup      String? // "Leather", "Chain", "Plate", etc.

  // Shield-specific fields
  shieldHp        Int?
  shieldHardness  Int?
  shieldBt        Int?    // Broken Threshold

  // Consumable/Equipment-specific fields
  activation      String? // "Cast A Spell", "[one-action]", etc.
  duration        String?
  usage           String?
  effect          String? // Specific effect text for item variants (Lesser, Moderate, Greater, Major)

  characterItems   CharacterItem[]
  formulas         CharacterFormula[]
  preparedItems    CharacterPreparedItem[]
}

model Spell {
  id          String   @id @default(uuid())
  name        String   @unique
  level       Int
  actions     String?
  traditions  String[]
  traits      String[]
  range       String?
  targets     String?
  duration    String?
  description String?
  url         String?

  characterSpells CharacterSpell[]
}

model Trait {
  id          String  @id @default(uuid())
  name        String  @unique
  description String?
  url         String?
}

// ==========================================
// TRANSLATION CACHE
// ==========================================

model Translation {
  id                  String             @id @default(uuid())
  type                TranslationType
  englishName         String
  germanName          String
  germanSummary       String?
  germanDescription   String?
  germanEffect        String?            // Translated effect text for alchemical items
  quality             TranslationQuality @default(MEDIUM)
  translatedBy        String             @default("claude-api")
  createdAt           DateTime           @default(now())
  updatedAt           DateTime           @updatedAt

  @@unique([type, englishName])
  @@index([type])
  @@index([englishName])
}
