import { afterEach, describe, mock, test } from 'node:test';
import assert from 'node:assert/strict';
import { Op } from 'sequelize';

import db from '@/db/models';
import StaffAttendanceService from '@/services/staff_attendance';
import { FEATURE_PERMISSIONS } from '@/shared/constants/product-permissions';
import { ROLE_NAMES, ROLE_SCOPES } from '@/shared/constants/roles';
import { createTestUser } from '@/test-utils';

function permission(name: string) {
  return { name };
}

function isRecord(value: unknown): value is Record<PropertyKey, unknown> {
  return typeof value === 'object' && value !== null;
}

afterEach(() => {
  mock.restoreAll();
});

describe('StaffAttendanceService', () => {
  test('includes school-owned users and school campuses in school report scope', async () => {
    const schoolUser = createTestUser({
      organizationId: '11111111-1111-4111-8111-111111111111',
      organizations: { id: '11111111-1111-4111-8111-111111111111' },
      schoolId: '22222222-2222-4222-8222-222222222222',
      campusId: null,
      app_role: {
        name: ROLE_NAMES.REGISTRAR,
        scope: ROLE_SCOPES.SCHOOL,
        globalAccess: false,
        permissions: [permission(FEATURE_PERMISSIONS.READ_STAFF_ATTENDANCE_REPORTS)],
      },
    });
    let capturedWhere: unknown = null;

    mock.method(db.staff_attendance_records, 'findAndCountAll', async (options: unknown) => {
      if (isRecord(options)) {
        capturedWhere = options.where;
      }
      return { rows: [], count: 0 };
    });

    await StaffAttendanceService.listRecords({}, schoolUser);

    assert.equal(isRecord(capturedWhere), true);
    if (!isRecord(capturedWhere)) {
      return;
    }
    assert.equal(Object.getOwnPropertySymbols(capturedWhere).includes(Op.or), true);
  });

  test('upserts a school office staff attendance record inside school scope', async () => {
    const organizationId = '11111111-1111-4111-8111-111111111111';
    const schoolId = '22222222-2222-4222-8222-222222222222';
    const actor = createTestUser({
      id: '44444444-4444-4444-8444-444444444444',
      organizationId,
      organizations: { id: organizationId },
      schoolId,
      campusId: null,
      app_role: {
        name: ROLE_NAMES.PRINCIPAL,
        scope: ROLE_SCOPES.SCHOOL,
        globalAccess: false,
        permissions: [permission(FEATURE_PERMISSIONS.FILL_ATTENDANCE)],
      },
    });
    let userWhere: unknown = null;

    mock.method(db.users, 'findOne', async (options: unknown) => {
      if (isRecord(options)) {
        userWhere = options.where;
      }
      return {
        get: () => ({
          id: '55555555-5555-4555-8555-555555555555',
          firstName: 'Nicole',
          lastName: 'Adams',
          email: 'registrar@flatlogic.com',
          campusId: null,
          app_role: { name: ROLE_NAMES.REGISTRAR },
        }),
      };
    });
    mock.method(db.sequelize, 'transaction', async () => ({
      commit: async () => undefined,
      rollback: async () => undefined,
    }));
    mock.method(db.staff_attendance_records, 'findOne', async () => null);
    mock.method(db.staff_attendance_records, 'create', async (payload: unknown) => ({
      get: () => ({
        id: '66666666-6666-4666-8666-666666666666',
        ...(isRecord(payload) ? payload : {}),
        createdAt: new Date('2026-06-17T12:00:00Z'),
        updatedAt: new Date('2026-06-17T12:00:00Z'),
      }),
    }));

    await StaffAttendanceService.upsertRecord(
      {
        userId: '55555555-5555-4555-8555-555555555555',
        date: '2026-06-17',
        status: 'present',
        note: '',
      },
      actor,
    );

    assert.equal(isRecord(userWhere), true);
    if (!isRecord(userWhere)) {
      return;
    }
    assert.equal(userWhere.schoolId, schoolId);
    assert.equal(userWhere.campusId, null);
  });

  test('upserts class staff attendance inside campus scope and stores class campus', async () => {
    const organizationId = '11111111-1111-4111-8111-111111111111';
    const campusId = '33333333-3333-4333-8333-333333333333';
    const actor = createTestUser({
      id: '44444444-4444-4444-8444-444444444444',
      organizationId,
      organizations: { id: organizationId },
      campusId,
      app_role: {
        name: ROLE_NAMES.DIRECTOR,
        scope: ROLE_SCOPES.CAMPUS,
        globalAccess: false,
        permissions: [permission(FEATURE_PERMISSIONS.FILL_ATTENDANCE)],
      },
    });
    let userWhere: unknown = null;
    let createdPayload: unknown = null;

    mock.method(db.users, 'findOne', async (options: unknown) => {
      if (isRecord(options)) {
        userWhere = options.where;
      }
      return {
        get: () => ({
          id: '55555555-5555-4555-8555-555555555555',
          firstName: 'Emily',
          lastName: 'Johnson',
          email: 'teacher@flatlogic.com',
          campusId: null,
          class: { campusId },
          app_role: { name: ROLE_NAMES.TEACHER },
        }),
      };
    });
    mock.method(db.sequelize, 'transaction', async () => ({
      commit: async () => undefined,
      rollback: async () => undefined,
    }));
    mock.method(db.staff_attendance_records, 'findOne', async () => null);
    mock.method(db.staff_attendance_records, 'create', async (payload: unknown) => {
      createdPayload = payload;
      return {
        get: () => ({
          id: '66666666-6666-4666-8666-666666666666',
          ...(isRecord(payload) ? payload : {}),
          createdAt: new Date('2026-06-17T12:00:00Z'),
          updatedAt: new Date('2026-06-17T12:00:00Z'),
        }),
      };
    });

    await StaffAttendanceService.upsertRecord(
      {
        userId: '55555555-5555-4555-8555-555555555555',
        date: '2026-06-17',
        status: 'present',
        note: '',
      },
      actor,
    );

    assert.equal(isRecord(userWhere), true);
    if (isRecord(userWhere)) {
      assert.equal(userWhere.organizationId, organizationId);
      assert.equal(Object.getOwnPropertySymbols(userWhere).includes(Op.or), true);
    }
    assert.equal(isRecord(createdPayload), true);
    if (isRecord(createdPayload)) {
      assert.equal(createdPayload.campusId, campusId);
    }
  });
});
