// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

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

model Taxonomy {
    id         String    @id @default(cuid())
    name       String    @unique
    slug       String    @unique @map("slug")
    deletedAt  DateTime? @map("deleted_at")
    createdAt  DateTime  @default(now()) @map("created_at")
    terms      Term[]
    objectType String[]  @map("object_type")
    order      Float?    @map("order")

    @@index([order, deletedAt])
    @@map("taxonomy")
}

model Term {
    id          String    @id @default(cuid())
    name        String
    // posts       Post[]
    posts       Post[]    @relation("post_term")
    taxonomy    Taxonomy? @relation(fields: [taxonomyId], references: [id])
    taxonomyId  String?   @map("taxonomy_id")
    order       Float?    @map("order")
    description String?
    parentId    String?   @map("parent_id")

    parent      Term?          @relation("ChildParent", fields: [parentId], references: [id], onDelete: Cascade)
    children    Term[]         @relation("ChildParent")
    ancestors   TermAncestry[] @relation("DescendantToAncestor")
    descendants TermAncestry[] @relation("AncestorToDescendant")
    domainId    String?        @map("domain_id")
    domain      Department?    @relation("TermDom", fields: [domainId], references: [id])
    createdAt   DateTime       @default(now()) @map("created_at")
    updatedAt   DateTime       @updatedAt @map("updated_at")
    deletedAt   DateTime?      @map("deleted_at")
    createdBy   String?        @map("created_by")
    depts       Department[]   @relation("department_term")
    hasChildren Boolean?       @default(false) @map("has_children")

    @@index([name]) // 对name字段建立索引，以加快基于name的查找速度
    @@index([parentId]) // 对parentId字段建立索引，以加快基于parentId的查找速度
    @@map("term")
}

model TermAncestry {
    id           String  @id @default(cuid())
    ancestorId   String? @map("ancestor_id")
    descendantId String  @map("descendant_id")
    relDepth     Int     @map("rel_depth")
    ancestor     Term?   @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
    descendant   Term    @relation("DescendantToAncestor", fields: [descendantId], references: [id])

    // 索引建议
    @@index([ancestorId]) // 针对祖先的查询
    @@index([descendantId]) // 针对后代的查询
    @@index([ancestorId, descendantId]) // 组合索引，用于查询特定的祖先-后代关系
    @@index([relDepth]) // 根据关系深度的查询
    @@map("term_ancestry")
}

model Staff {
    id       String  @id @default(cuid())
    showname String? @map("showname")
    username String  @unique @map("username")
    avatar   String? @map("avatar")
    password String? @map("password")

    phoneNumber String? @unique @map("phone_number")

    domainId String? @map("domain_id")
    deptId   String? @map("dept_id")

    domain     Department? @relation("DomainStaff", fields: [domainId], references: [id])
    department Department? @relation("DeptStaff", fields: [deptId], references: [id])
    order      Float?

    createdAt DateTime  @default(now()) @map("created_at")
    updatedAt DateTime  @updatedAt @map("updated_at")
    enabled   Boolean?  @default(true)
    deletedAt DateTime? @map("deleted_at")
    officerId String?   @map("officer_id")

    visits         Visit[]
    ownedPosts     Post[]     @relation("post_author")
    receviedPosts  Post[]     @relation("post_receiver")
    sentMsgs       Message[]  @relation("message_sender")
    receivedMsgs   Message[]  @relation("message_receiver")
    registerToken  String?
    ownedResources Resource[]
    meta           Json?

    @@index([officerId])
    @@index([deptId])
    @@index([domainId])
    @@index([username])
    @@index([order])
    @@map("staff")
}

model Department {
    id           String         @id @default(cuid())
    name         String
    order        Float?
    ancestors    DeptAncestry[] @relation("DescendantToAncestor")
    descendants  DeptAncestry[] @relation("AncestorToDescendant")
    parentId     String?        @map("parent_id")
    parent       Department?    @relation("ChildParent", fields: [parentId], references: [id])
    children     Department[]   @relation("ChildParent")
    domainId     String?        @map("domain_id")
    domainTerms  Term[]         @relation("TermDom")
    deletedAt    DateTime?      @map("deleted_at")
    isDomain     Boolean?       @default(false) @map("is_domain")
    domainStaffs Staff[]        @relation("DomainStaff")
    deptStaffs   Staff[]        @relation("DeptStaff")
    terms        Term[]         @relation("department_term")

    hasChildren Boolean? @default(false) @map("has_children")

    @@index([parentId])
    @@index([isDomain])
    @@index([name])
    @@index([order])
    @@map("department")
}

model DeptAncestry {
    id           String      @id @default(cuid())
    ancestorId   String?     @map("ancestor_id")
    descendantId String      @map("descendant_id")
    relDepth     Int         @map("rel_depth")
    ancestor     Department? @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
    descendant   Department  @relation("DescendantToAncestor", fields: [descendantId], references: [id])

    // 索引建议
    @@index([ancestorId]) // 针对祖先的查询
    @@index([descendantId]) // 针对后代的查询
    @@index([ancestorId, descendantId]) // 组合索引，用于查询特定的祖先-后代关系
    @@index([relDepth]) // 根据关系深度的查询
    @@map("dept_ancestry")
}

model RoleMap {
    id         String  @id @default(cuid())
    objectId   String  @map("object_id")
    roleId     String  @map("role_id")
    domainId   String? @map("domain_id")
    objectType String  @map("object_type")
    role       Role    @relation(fields: [roleId], references: [id])

    @@index([domainId])
    @@index([objectId])
    @@map("rolemap")
}

model Role {
    id          String    @id @default(cuid())
    name        String    @unique @map("name")
    permissions String[]  @default([]) @map("permissions")
    roleMaps    RoleMap[]
    system      Boolean?  @default(false) @map("system")
    createdAt   DateTime  @default(now()) @map("created_at")
    updatedAt   DateTime  @updatedAt @map("updated_at")
    deletedAt   DateTime? @map("deleted_at")

    @@map("role")
}

model AppConfig {
    id          String  @id @default(cuid())
    slug        String  @unique
    title       String?
    description String?
    meta        Json?

    @@map("app_config")
}

model Post {
    // 字符串类型字段
    id        String     @id @default(cuid()) // 帖子唯一标识，使用 cuid() 生成默认值
    type      String? // 帖子类型，可为空
    state     String? // 状态 ： 未读、处理中、已回答
    title     String? // 帖子标题，可为空
    content   String? // 帖子内容，可为空
    domainId  String?    @map("domain_id")
    terms     Term[]     @relation("post_term")
    // 日期时间类型字段
    createdAt DateTime?  @default(now()) @map("created_at")
    updatedAt DateTime?  @map("updated_at")
    deletedAt DateTime?  @map("deleted_at") // 删除时间，可为空
    // 关系类型字段
    authorId  String?    @map("author_id")
    author    Staff?     @relation("post_author", fields: [authorId], references: [id]) // 帖子作者，关联 Staff 模型
    visits    Visit[] // 访问记录，关联 Visit 模型
    views     Int?       @default(0)
    likes     Int?       @default(0)
    hates     Int?       @default(0)
    receivers Staff[]    @relation("post_receiver")
    parentId  String?    @map("parent_id")
    parent    Post?      @relation("PostChildren", fields: [parentId], references: [id]) // 父级帖子，关联 Post 模型
    children  Post[]     @relation("PostChildren") // 子级帖子列表，关联 Post 模型
    resources Resource[] // 附件列表
    isPublic  Boolean?   @default(true) @map("is_public")
    meta      Json? // 签名 和 IP 和 tags

    // 复合索引
    @@index([type, domainId]) // 类型和域组合查询
    @@index([authorId, type]) // 作者和类型组合查询
    @@index([parentId, type]) // 父级帖子和创建时间索引
    // 时间相关索引
    @@index([createdAt]) // 按创建时间倒序索引
    @@index([updatedAt]) // 按更新时间倒序索引
}

model Message {
    id        String    @id @default(cuid())
    url       String?
    intent    String?
    option    Json?
    senderId  String?   @map("sender_id")
    type      String?
    sender    Staff?    @relation(name: "message_sender", fields: [senderId], references: [id])
    title     String?
    content   String?
    receivers Staff[]   @relation("message_receiver")
    visits    Visit[]
    createdAt DateTime  @default(now()) @map("created_at")
    updatedAt DateTime? @updatedAt @map("updated_at")

    @@index([type, createdAt])
    @@map("message")
}

model Visit {
    id        String   @id @default(cuid()) @map("id")
    type      String?
    views     Int      @default(1) @map("views")
    // sourceIP  String?  @map("source_ip")
    // 关联关系
    visitorId String?  @map("visitor_id")
    visitor   Staff?   @relation(fields: [visitorId], references: [id])
    postId    String?  @map("post_id")
    post      Post?    @relation(fields: [postId], references: [id])
    message   Message? @relation(fields: [messageId], references: [id])
    messageId String?  @map("message_id")
    createdAt DateTime @default(now()) @map("created_at") // 创建时间
    updatedAt DateTime @updatedAt @map("updated_at") // 更新时间
    meta      Json?

    @@index([postId, type, visitorId])
    @@index([messageId, type, visitorId])
    @@map("visit")
}

model Resource {
    id          String    @id @default(cuid()) @map("id")
    title       String?   @map("title")
    description String?   @map("description")
    type        String?   @map("type")
    fileId      String?   @unique
    url         String?
    meta        Json?     @map("meta")
    status      String?
    createdAt   DateTime? @default(now()) @map("created_at")
    updatedAt   DateTime? @updatedAt @map("updated_at")
    createdBy   String?   @map("created_by")
    updatedBy   String?   @map("updated_by")
    deletedAt   DateTime? @map("deleted_at")

    isPublic Boolean? @default(true) @map("is_public")
    owner    Staff?   @relation(fields: [ownerId], references: [id])
    ownerId  String?  @map("owner_id")
    post     Post?    @relation(fields: [postId], references: [id])
    postId   String?  @map("post_id")

    // 索引
    @@index([type])
    @@index([createdAt])
    @@map("resource")
}
