// Mock @prisma/client for E2E tests.
// PrismaService extends PrismaClient → this must be a plain class.
// Model access (prisma.user.findMany()) is supported via prototype delegates.

function modelMethods(): Record<string, Function> {
  return {
    findUnique: () => Promise.resolve(null),
    findFirst: () => Promise.resolve(null),
    findMany: () => Promise.resolve([]),
    findRaw: () => Promise.resolve([]),
    create: (args: any) => Promise.resolve({ id: 1, ...args?.data }),
    update: (args: any) => Promise.resolve({ id: 1, ...args?.data }),
    delete: () => Promise.resolve({ id: 1 }),
    upsert: (args: any) => Promise.resolve({ id: 1, ...args?.create }),
    count: () => Promise.resolve(0),
    aggregate: () => Promise.resolve({}),
    groupBy: () => Promise.resolve([]),
    createMany: () => Promise.resolve({ count: 1 }),
    deleteMany: () => Promise.resolve({ count: 0 }),
    updateMany: () => Promise.resolve({ count: 0 }),
    aggregateRaw: () => Promise.resolve([]),
  }
}

function createModelDelegate(): any {
  const methods = modelMethods()
  return new Proxy(methods, {
    get(target: any, prop: string) {
      if (prop === 'then') return undefined
      if (prop in target) return target[prop]
      return () => Promise.resolve(undefined)
    },
  })
}

// admin user fixture so login tests can get a real JWT
const ADMIN_USER = {
  id: 'admin-test-001',
  email: 'admin@zhixi.app',
  displayName: 'Test Admin',
  passwordHash: '$2b$10$mp8kF.PwWBjb0fp/5d0nZ.VNofYcVm7jhJYtswxLfGU/EJW5K8qCm', // bcrypt hash of "admin123"
  role: 'SUPER_ADMIN',
  status: 'ACTIVE',
  twoFactorEnabled: false,
  failedLoginCount: 0,
  lockedUntil: null,
  deletedAt: null,
  lastLoginAt: null,
  lastLoginIp: null,
  createdAt: new Date(),
  updatedAt: new Date(),
}

const ADMIN_SESSION = {
  id: 1,
  adminUserId: 'admin-test-001',
  refreshTokenHash: 'test-hash',
  ip: null,
  userAgent: null,
  revokedAt: null,
  expiresAt: new Date(Date.now() + 7 * 86400000),
  createdAt: new Date(),
}

export class PrismaClient {
  $connect() { return Promise.resolve() }
  $disconnect() { return Promise.resolve() }
  $on() {}
  $transaction(fn: any) {
    const delegate = createModelDelegate()
    return typeof fn === 'function' ? fn(delegate) : Promise.resolve([])
  }
  $executeRaw() { return Promise.resolve(0) }
  $queryRaw() { return Promise.resolve([]) }
  $runCommandRaw() { return Promise.resolve({}) }
}

const modelNames = [
  'user', 'authAccount', 'refreshToken', 'userProfile', 'userPreference',
  'userConsent', 'knowledgeBase', 'knowledgeItem', 'knowledgeItemRelation',
  'tag', 'knowledgeItemTag', 'uploadedFile', 'documentImport',
  'learningSession', 'learningRecord', 'activeRecallQuestion',
  'activeRecallAnswer', 'aiAnalysisJob', 'aiAnalysisResult', 'focusItem',
  'reviewCard', 'reviewLog', 'reviewPlan', 'dailyLearningActivity',
  'notification', 'feedback', 'aiUsageLog', 'waitlistEntry', 'appChangelog',
  'knowledgeSource', 'knowledgeChunk', 'importCandidate', 'backupJob',
  'adminUser', 'adminSession', 'adminAuditLog', 'membershipPlan',
  'adminConversation', 'adminMessage', 'adminCostItem', 'appConfig',
  'featureFlag', 'configChangeLog', 'securityEvent', 'sensitiveWord',
  'contentSafetyCheck', 'contentReport', 'apiMetric', 'taskLog',
  'userMembership', 'quotaUsage', 'costDailySummary', 'secretRecord',
  'secretAccessLog', 'modelRoute', 'providerConfig', 'fallbackEvent',
  'violationRecord', 'contentReport', 'userDevice', 'accountDeletionRequest',
  'workspace', 'knowledgeFolder', 'sourceReference', 'importStepLog',
  'recentItem', 'favorite', 'searchHistory',
  'chatSession', 'chatMessage', 'chatCitation',
  'artifact', 'learningGoal', 'streakRecord',
  'notificationPreference', 'pushToken', 'notificationTemplate',
  'learningGoal', 'streakRecord', 'learningStats',
]

for (const name of modelNames) {
  ;(PrismaClient.prototype as any)[name] = createModelDelegate()
}

// Patch adminUser.findUnique so login tests can succeed
const origAdminUser = (PrismaClient.prototype as any).adminUser
;(PrismaClient.prototype as any).adminUser = new Proxy(origAdminUser, {
  get(target: any, prop: string) {
    if (prop === 'findUnique') {
      return (args: any) => {
        if (args?.where?.email === ADMIN_USER.email) return Promise.resolve(ADMIN_USER)
        if (args?.where?.id === ADMIN_USER.id) return Promise.resolve(ADMIN_USER)
        return target.findUnique(args)
      }
    }
    if (prop === 'findFirst') {
      return (args: any) => {
        if (args?.where?.email === ADMIN_USER.email) return Promise.resolve(ADMIN_USER)
        return target.findFirst(args)
      }
    }
    return target[prop]
  },
})

// Patch adminSession so admin auth guard doesn't reject
const origAdminSession = (PrismaClient.prototype as any).adminSession
;(PrismaClient.prototype as any).adminSession = new Proxy(origAdminSession, {
  get(target: any, prop: string) {
    if (prop === 'findUnique' || prop === 'findFirst') {
      return (_args?: any) => Promise.resolve(ADMIN_SESSION)
    }
    return target[prop]
  },
})

// Patch user so JwtAuthGuard status check passes for test users
const TEST_USER = {
  id: 'test-user',
  email: 'test@test.com',
  role: 'USER',
  status: 'active',
  deletedAt: null,
}
const origUser = (PrismaClient.prototype as any).user
;(PrismaClient.prototype as any).user = new Proxy(origUser, {
  get(target: any, prop: string) {
    if (prop === 'findUnique') {
      return (args: any) => {
        if (args?.where?.id === 'test-user') return Promise.resolve(TEST_USER)
        if (args?.where?.id === 'disabled-user') return Promise.resolve({ ...TEST_USER, id: 'disabled-user', status: 'disabled' })
        if (args?.where?.id === 'deleted-user') return Promise.resolve({ ...TEST_USER, id: 'deleted-user', deletedAt: new Date() })
        return target.findUnique(args)
      }
    }
    return target[prop]
  },
})

// Patch refreshToken so the refresh flow works in tests
const knownRefreshHashes = new Set<string>()
const origRefreshToken = (PrismaClient.prototype as any).refreshToken
;(PrismaClient.prototype as any).refreshToken = new Proxy(origRefreshToken, {
  get(target: any, prop: string) {
    if (prop === 'findFirst') {
      return (args: any) => {
        const hash = args?.where?.tokenHash
        if (hash && knownRefreshHashes.has(hash)) {
          return Promise.resolve({
            id: 'rt-test-001',
            userId: 'test-user',
            tokenHash: hash,
            deviceId: null,
            deviceName: null,
            expiresAt: new Date(Date.now() + 7 * 86400000),
            revokedAt: null,
            user: { ...TEST_USER },
          })
        }
        return Promise.resolve(null)
      }
    }
    if (prop === 'update') {
      return () => Promise.resolve({ id: 'rt-test-001' })
    }
    if (prop === 'updateMany') {
      return () => Promise.resolve({ count: 1 })
    }
    if (prop === 'create') {
      return (args: any) => {
        if (args?.data?.tokenHash) {
          knownRefreshHashes.add(args.data.tokenHash)
        }
        return Promise.resolve({ id: 'rt-test-new', ...args?.data })
      }
    }
    return target[prop]
  },
})

export const Prisma = {
  ModelName: {},
  PrismaClientKnownRequestError: class extends Error {
    code: string
    constructor(message: string, opts: { code: string; clientVersion: string }) {
      super(message)
      this.code = opts.code
    }
  },
  PrismaClientValidationError: class extends Error {},
  PrismaClientInitializationError: class extends Error {},
}
