import { arr, bool, dateTime, int, num, obj, objectId, ref, str, anyObj } from './helpers';

const timestamps = { createdAt: dateTime(), updatedAt: dateTime() };
const kolkata = (example: string) => str(example, { description: 'Asia/Kolkata local time' });

export const schemas = {
  // ─── Envelope ──────────────────────────────────────────────────────────────
  ErrorResponse: obj({
    success: bool(false),
    status_code: int(400),
    message: str('Something went wrong'),
    data: { nullable: true, example: null },
    errors: str('Something went wrong'),
    pagination: { type: 'object', nullable: true, example: null },
  }),
  Pagination: obj({
    total: int(42),
    page: int(1),
    limit: int(20),
    totalPages: int(3),
    hasNextPage: bool(true),
    hasPrevPage: bool(false),
  }),

  // ─── Accounts ──────────────────────────────────────────────────────────────
  AuthAdmin: obj({ id: objectId(), name: str('Super Admin'), email: str('admin@eglogics.com'), role: str('admin') }),
  AuthUser: obj({
    id: objectId(),
    name: str('John Doe'),
    email: str('john@eglogics.com'),
    role: str('user'),
    employee_id: str('EG-0045', { nullable: true }),
    avatar: str(null, { nullable: true }),
  }),
  Admin: obj({
    _id: objectId(),
    name: str('Super Admin'),
    email: str('admin@eglogics.com'),
    role: str('admin'),
    avatar: str(null, { nullable: true }),
    twoFactorEnabled: bool(false),
    twoFactorVerifiedAt: dateTime({ nullable: true }),
    ...timestamps,
  }),
  User: obj({
    _id: objectId(),
    name: str('John Doe'),
    email: str('john@eglogics.com'),
    role: str('user'),
    avatar: str('https://res.cloudinary.com/xxx/avatars/abc.jpg', { nullable: true }),
    phone: str('9812345670', { nullable: true }),
    address: str(null, { nullable: true }),
    department: str('Engineering', { nullable: true }),
    designation: str('Full Stack Developer', { nullable: true }),
    employee_id: str('EG-0045', { nullable: true }),
    joining_date: dateTime({ nullable: true }),
    quiz_points: num(120),
    sudoku_points: num(40),
    zipline_points: num(25),
    spin_wheel_points: num(10),
    earned_points: num(195),
    redeemed_points: num(50),
    currentStreak: int(3),
    longestStreak: int(9),
    lastCheckInDate: str('2026-09-30', { nullable: true }),
    status: str('active', { enum: ['active', 'inactive'] }),
    ...timestamps,
  }),
  AdminUserListItem: {
    allOf: [
      ref('User'),
      obj({
        has_password: bool(true, { description: 'false until the employee completes the set-password invite' }),
        attendance: str('Present', { enum: ['Present', 'Absent'], description: 'Has a tracker CHECKIN today (Asia/Kolkata)' }),
      }),
    ],
  },
  EditableUserFields: obj({
    name: str('John Doe'),
    email: str('john@eglogics.com'),
    phone: str('9812345670'),
    address: str('221B Baker Street'),
    department: str('Engineering'),
    designation: str('Full Stack Developer'),
    employee_id: str('EG-0045'),
    joining_date: str('2026-04-01', { format: 'date' }),
    status: str('active', { enum: ['active', 'inactive'] }),
  }),

  // ─── Tracker / attendance ──────────────────────────────────────────────────
  OsInfo: obj({ os: str('Windows 11 Pro'), network: str('Wi-Fi') }),
  DesktopLogType: str('CHECKIN', { enum: ['BREAK_START', 'BREAK_END', 'IDLE', 'ACTIVE', 'CHECKOUT', 'CHECKIN', 'BREAK'] }),
  BreakType: str('Lunch', {
    enum: ['Training', 'Meeting', 'Lunch', 'Tea', 'Personal', 'Other', 'TRACKING_INTERRUPTED'],
    description: 'TRACKING_INTERRUPTED is system-only (not returned by /break-types) and is deducted from working time',
  }),
  DesktopSessionEvent: obj({
    _id: objectId(),
    log_type: ref('DesktopLogType'),
    timestamp: kolkata('2026-09-30 09:31:05'),
    createdAt: kolkata('2026-09-30 09:31:06'),
    ip_address: str('192.168.1.24'),
    os_info: ref('OsInfo'),
    device_name: str('EG-LAPTOP-12'),
    break_type: ref('BreakType'),
    end_time: kolkata('2026-09-30 13:30:00'),
    duration_seconds: int(1800),
    is_auto_checkout: bool(false, { description: 'Only on CHECKOUT events; true when inserted by the auto-checkout cron' }),
  }),
  DaySummary: obj({
    user: obj({ _id: objectId(), name: str('John Doe'), email: str('john@eglogics.com'), department: str('Engineering', { nullable: true }) }),
    date: str('2026-09-30', { description: 'yyyy-MM-dd (Asia/Kolkata)' }),
    logs: arr(
      obj({
        type: ref('DesktopLogType'),
        time: str('09:31:05'),
        createdAt: kolkata('2026-09-30 09:31:06'),
        ip_address: str('192.168.1.24'),
        os_info: ref('OsInfo'),
        device_name: str('EG-LAPTOP-12'),
        break_type: ref('BreakType'),
        end_time: kolkata('2026-09-30 13:30:00'),
        duration_seconds: int(1800),
        is_auto_checkout: bool(false),
      }),
    ),
    firstCheckIn: str('09:31:05', { nullable: true }),
    lastCheckOut: str('18:45:10', { nullable: true }),
    autoCheckedOut: bool(false),
    totalCheckinTime: int(33245, { description: 'Seconds from first CHECKIN to last CHECKOUT' }),
    totalBreakTime: int(3600, { description: 'Seconds' }),
    totalIdleTime: int(900, { description: 'Seconds' }),
    totalInterruptedTime: int(0, { description: 'Seconds' }),
    workingTime: int(28745, { description: 'Seconds' }),
    status: str('Completed', { enum: ['Completed', 'In Progress'] }),
  }),
  DailyAttendanceRow: obj({
    userId: objectId(),
    name: str('John Doe'),
    email: str('john@eglogics.com'),
    department: str('Engineering', { nullable: true }),
    firstCheckIn: str('09:31:05', { nullable: true }),
    lastCheckOut: str('18:45:10', { nullable: true }),
    workingTime: int(28745, { description: 'Seconds' }),
    totalBreakTime: int(3600, { description: 'Seconds' }),
    totalIdleTime: int(900, { description: 'Seconds' }),
    totalInterruptedTime: int(0, { description: 'Seconds' }),
    autoCheckedOut: bool(false),
    status: str('Completed', { enum: ['Completed', 'In Progress', 'Absent'] }),
    sessions: arr(obj({ check_in: dateTime(), check_out: dateTime({ nullable: true }) })),
  }),
  WebAttendanceSession: obj({ check_in: kolkata('2026-09-30 09:31:05'), check_out: { ...kolkata('2026-09-30 18:45:10'), nullable: true } }),
  DesktopRelease: obj({
    _id: objectId(),
    version: str('1.0.4'),
    platform: str('windows', { enum: ['windows', 'macos', 'linux'] }),
    installer_filename: str('EGInTimeSetup_windows_v1.0.4.exe'),
    original_filename: str('EGInTime Setup 1.0.4.exe'),
    release_notes: arr(str('Fixed idle detection')),
    mandatory: bool(false),
    is_active: bool(true),
    file_size: int(84512345, { description: 'Bytes' }),
    release_date: dateTime(),
    download_url: str('https://tracker-api.eglogics.com/downloads/EGInTimeSetup_windows_v1.0.4.exe'),
    ...timestamps,
  }),
  SyncSession: obj({
    _id: objectId(),
    user: objectId(),
    local_id: int(12),
    login_time: dateTime(),
    logout_time: dateTime({ nullable: true }),
    total_work_seconds: int(14400),
    total_break_seconds: int(1800),
    total_idle_seconds: int(600),
    status: str('active'),
    device_name: str('EG-LAPTOP-12'),
    operating_system: str('Windows 11 Pro'),
    ip_address: str('192.168.1.24'),
    ...timestamps,
  }),
  SyncData: obj({
    sessions: arr(ref('SyncSession')),
    tracking_events: arr(anyObj('Synced tracking event (event_type, event_time, metadata, …)')),
    resource_usage: arr(anyObj('Synced resource sample (cpu_usage_percent, ram_usage_mb, …, recorded_at)')),
    session_periods: arr(anyObj('Synced period (type, start_time, end_time, duration_seconds, remarks)')),
  }),

  // ─── Quizzes & questions ───────────────────────────────────────────────────
  Question: obj({
    _id: objectId(),
    question_text: str('What does HTTP stand for?'),
    option_a: str('HyperText Transfer Protocol'),
    option_b: str('High Transfer Text Protocol'),
    option_c: str('Hyperlink Text Transfer Protocol'),
    option_d: str('None of the above'),
    correct_option: str('HyperText Transfer Protocol', { description: 'Must equal the text of one of the four options' }),
    difficulty: str('medium', { enum: ['easy', 'medium', 'hard'] }),
    category: str('Web', { nullable: true }),
    tags: arr(str('networking')),
    points: num(1),
    ...timestamps,
  }),
  QuestionInput: obj(
    {
      question_text: str('What does HTTP stand for?'),
      option_a: str('HyperText Transfer Protocol'),
      option_b: str('High Transfer Text Protocol'),
      option_c: str('Hyperlink Text Transfer Protocol'),
      option_d: str('None of the above'),
      correct_option: str('HyperText Transfer Protocol'),
      difficulty: str('medium', { enum: ['easy', 'medium', 'hard'] }),
      category: str('Web'),
      tags: arr(str('networking')),
      points: num(1),
    },
    ['question_text', 'option_a', 'option_b', 'option_c', 'option_d', 'correct_option'],
  ),
  Quiz: obj({
    _id: objectId(),
    title: str('JavaScript Basics'),
    questions: arr(anyObj('Populated question (fields vary by endpoint)')),
    start_datetime: dateTime(),
    end_datetime: dateTime(),
    status: str('active', { enum: ['draft', 'active', 'inactive'] }),
    ...timestamps,
  }),
  QuizResult: obj({
    _id: objectId(),
    quiz: objectId(),
    user: anyObj('User id, or { _id, name, email } when populated'),
    answers: arr(
      obj({
        question: anyObj('Question id, or the populated question'),
        selected_option: str('HyperText Transfer Protocol'),
        is_correct: bool(true),
        points_earned: num(1),
      }),
    ),
    score: num(15),
    total_points: num(20),
    submitted_at: dateTime(),
  }),
  ImportResult: obj({
    total: int(50),
    inserted: int(47),
    failed_count: int(3),
    failed: arr(
      obj({
        row: int(12, { description: 'CSV line number (header is line 1)' }),
        data: anyObj('The raw CSV row'),
        reasons: arr(str('Missing or empty field: "option_c"')),
      }),
    ),
  }),

  // ─── Psychometric ──────────────────────────────────────────────────────────
  PsychometricStatement: obj({
    _id: objectId(),
    statement_text: str('I enjoy meeting new people'),
    dimension: str('EI', { enum: ['EI', 'SN', 'TF', 'JP'] }),
    direction: str('positive', { enum: ['positive', 'negative'] }),
    sequence: int(1, { nullable: true }),
    ...timestamps,
  }),
  PsychometricTest: obj({
    _id: objectId(),
    title: str('MBTI Assessment'),
    description: str(null, { nullable: true }),
    statements: arr(anyObj('Statement id, or the populated statement')),
    status: str('active', { enum: ['draft', 'active', 'inactive'] }),
    ...timestamps,
  }),
  DimensionScore: obj({ first: num(62, { description: 'E / S / T / J %' }), second: num(38, { description: 'I / N / F / P %' }) }),
  PersonalityProfile: obj({
    EI: ref('DimensionScore'),
    SN: ref('DimensionScore'),
    TF: ref('DimensionScore'),
    JP: ref('DimensionScore'),
  }),
  PsychometricResult: obj({
    _id: objectId(),
    test: anyObj('Test id, or { _id, title, description } when populated'),
    user: anyObj('User id, or { _id, name, email, department, designation } when populated'),
    responses: arr(obj({ statement: anyObj('Statement id or populated statement'), value: int(4, { minimum: 1, maximum: 5 }) })),
    profile: ref('PersonalityProfile'),
    personality_type: str('ENTP'),
    submitted_at: dateTime(),
  }),

  // ─── Certificates ──────────────────────────────────────────────────────────
  CertificateRequest: obj({
    _id: objectId(),
    user: anyObj('User id, or populated user on admin endpoints'),
    certificate_id: str('WEBDEV2234'),
    title: str('AWS Cloud Practitioner'),
    description: str(null, { nullable: true }),
    issuer: str('Amazon Web Services'),
    issue_date: dateTime(),
    completion_date: dateTime({ nullable: true }),
    certificate_url: str('https://res.cloudinary.com/xxx/certificates/abc.pdf'),
    status: str('pending', { enum: ['pending', 'approved', 'rejected'] }),
    admin_comment: str(null, { nullable: true }),
    reviewed_by: objectId(),
    reviewed_at: dateTime({ nullable: true }),
    ...timestamps,
  }),
  UserCertificate: obj({
    _id: objectId(),
    certificate_id: str('WEBDEV2234'),
    user: objectId(),
    request: objectId(),
    title: str('AWS Cloud Practitioner'),
    description: str(null, { nullable: true }),
    issuer: str('Amazon Web Services'),
    issue_date: dateTime(),
    completion_date: dateTime({ nullable: true }),
    certificate_url: str('https://res.cloudinary.com/xxx/certificates/abc.pdf'),
    ...timestamps,
  }),

  // ─── Rewards ───────────────────────────────────────────────────────────────
  Reward: obj({
    _id: objectId(),
    name: str('Amazon Gift Card'),
    description: str('₹500 Amazon voucher'),
    type: str('digital', { enum: ['physical', 'digital'] }),
    points_required: num(500),
    quantity: int(10, { description: 'Omitted = unlimited stock' }),
    image_url: str('https://res.cloudinary.com/xxx/rewards/card.png'),
    is_active: bool(true),
    ...timestamps,
  }),
  RewardRedemption: obj({
    _id: objectId(),
    user: anyObj('User id, or populated { _id, name, email }'),
    reward: anyObj('Reward id, or the populated reward'),
    status: str('pending', { enum: ['pending', 'approved', 'rejected', 'fulfilled'] }),
    requestedAt: dateTime(),
    processedAt: dateTime(),
    adminNote: str('Out of budget this quarter'),
  }),

  // ─── Games ─────────────────────────────────────────────────────────────────
  SudokuPuzzle: obj({
    _id: objectId(),
    type: str('sudoku'),
    difficulty: str('medium', { enum: ['easy', 'medium', 'hard'] }),
    puzzle: str('530070000600195000098000060800060003400803001700020006060000280000419005000080079', {
      description: '81-character grid, row by row; 0 = empty cell',
    }),
    solution: str(undefined, { description: '81-character solved grid (admin endpoints only)' }),
    is_active: bool(true),
    createdAt: dateTime(),
  }),
  ZiplineCell: obj({ row: int(0), col: int(0) }, ['row', 'col']),
  ZiplineCheckpoint: obj({ row: int(0), col: int(0), value: int(1) }, ['row', 'col', 'value']),
  ZiplinePuzzle: obj({
    _id: objectId(),
    title: str('Warm-up'),
    description: str('Connect 1 to 4'),
    difficulty: str('easy', { enum: ['easy', 'medium', 'hard'] }),
    grid: arr(arr(int(0))),
    numbers: arr(ref('ZiplineCheckpoint')),
    blocks: arr(ref('ZiplineCell')),
    is_active: bool(true),
    createdAt: dateTime(),
  }),
  ZiplinePuzzleInput: obj(
    {
      title: str('Warm-up'),
      description: str('Connect 1 to 4'),
      difficulty: str('easy', { enum: ['easy', 'medium', 'hard'] }),
      grid: { ...arr(arr(int(0))), description: 'Layout only — every cell must be an integer', example: [[0, 0, 0], [0, 0, 0], [0, 0, 0]] },
      numbers: { ...arr(ref('ZiplineCheckpoint')), description: 'Checkpoints; values must be sequential 1..N with unique coordinates' },
      blocks: { ...arr(ref('ZiplineCell')), description: 'Blocked cells (within grid bounds)' },
      solution: anyObj('Optional — accepted but not persisted by the current model'),
    },
    ['title', 'description', 'grid', 'numbers'],
  ),
  WheelSegment: obj(
    {
      _id: objectId(),
      label: str('50 Points'),
      prizeType: str('points', { enum: ['points', 'voucher', 'gift', 'retry', 'none'] }),
      prizeValue: num(50, { description: 'Defaults to 0; for points prizes this is added to earned_points' }),
      weight: num(10, { description: 'Relative probability; total weight must be > 0' }),
      color: str('#FFB020'),
    },
    ['label', 'prizeType', 'weight'],
  ),
  Wheel: obj({
    _id: objectId(),
    name: str('October Wheel'),
    isActive: bool(true),
    segments: arr(ref('WheelSegment')),
    ...timestamps,
  }),
  AvailableGame: obj({
    _id: objectId(),
    title: str('Sudoku'),
    subtitle: str('Up to 500 pts'),
    icon: str('grid'),
    color: str('green'),
    route: str('/sudoku'),
    is_active: bool(true),
    order: int(1),
  }),

  // ─── Misc ──────────────────────────────────────────────────────────────────
  Department: obj({ _id: objectId(), name: str('Engineering'), is_active: bool(true) }),
  Designation: obj({ _id: objectId(), name: str('Full Stack Developer'), is_active: bool(true), department: objectId() }),
  LegalPage: obj({
    _id: objectId(),
    type: str('privacy', { description: 'Content pages use privacy | terms | user-manual' }),
    title: str('Privacy Policy'),
    content: str('<p>Sanitised rich-text HTML…</p>'),
    updatedAt: dateTime(),
  }),
  Notification: obj({
    _id: objectId(),
    title: str('New quiz published'),
    message: str('Quiz 14 is now available.'),
    type: str('QUIZ_PUBLISHED', {
      enum: [
        'QUIZ_PUBLISHED',
        'QUIZ_REMINDER',
        'QUIZ_ENDING_SOON',
        'QUIZ_RESULT',
        'ATTENDANCE_STREAK',
        'CERTIFICATE_APPROVED',
        'CERTIFICATE_REJECTED',
        'ATTENDANCE_REMINDER',
        'REWARD',
        'GENERAL',
      ],
    }),
    isRead: bool(false),
    meta: anyObj('Event-specific data (ids, status, …)'),
    createdAt: dateTime(),
  }),
};
