import { v4 as uuid } from 'uuid';
import { Op, QueryTypes, type QueryInterface } from 'sequelize';
import {
  SEED_ORGANIZATION_ID,
  SEED_ORGANIZATION_2_ID,
  SEED_SECONDARY_CAMPUS_ID,
  SEED_SECONDARY_SCHOOL_ID,
  SEED_FIXTURE_USERS,
  SEED_SECONDARY_USERS,
  SEED_SCHOOL_CAMPUS_IDS,
  SEED_SCHOOL_ID,
  SEED_SCHOOL_2_ID,
} from '@/shared/constants/seed-fixtures';
import { ROLE_NAMES } from '@/shared/constants/roles';
import {
  POLICY_DOCUMENT_CATEGORIES,
  type PolicyDocumentCategory,
} from '@/shared/constants/policy-documents';
import { formatPersonName } from '@/shared/constants/users';
import { CONTENT_CATALOG_SEED_PAYLOADS } from './content-catalog-data/content-catalog-seed-payloads';

/**
 * Seeds the unified `policy_documents` for the Safety Protocols and Handbook &
 * Policies pages (Workstream 11). Safety protocols reuse the existing
 * content-catalog `safetyProtocols` payload (steps + autism considerations);
 * a few handbook policies give the handbook page demo content. The same current
 * document set is preset at organization, school, and campus content scopes for
 * the seeded tenants so every leadership dashboard has documents to track.
 * Idempotent by scope-aware `importHash`.
 */
interface SeedRow {
  readonly importHash: string;
  readonly title: string;
  readonly category: PolicyDocumentCategory;
  readonly tag: string;
  readonly body: string | null;
  readonly steps: readonly string[] | null;
  readonly autismConsiderations: readonly string[] | null;
}

const SAFETY_ROWS: SeedRow[] = CONTENT_CATALOG_SEED_PAYLOADS.safetyProtocols.map(
  (protocol) => ({
    importHash: `policy-doc-safety-${protocol.id}`,
    title: protocol.title,
    category: POLICY_DOCUMENT_CATEGORIES.SAFETY_PROTOCOL,
    tag: protocol.iconId,
    body: null,
    steps: protocol.steps,
    autismConsiderations: protocol.autismConsiderations,
  }),
);

const HANDBOOK_ROWS: SeedRow[] = [
  {
    importHash: 'policy-doc-handbook-behavior',
    title: 'Student Behavior Intervention Policy',
    category: POLICY_DOCUMENT_CATEGORIES.HANDBOOK_POLICY,
    tag: 'Behavior',
    body: 'All behavior interventions must follow the least-restrictive approach. Staff must document all incidents using the Behavior Incident Report form within 24 hours. Physical intervention is only permitted when there is imminent danger to the individual or others, and must follow de-escalation protocols. All physical interventions must be reported to administration immediately.',
    steps: null,
    autismConsiderations: null,
  },
  {
    importHash: 'policy-doc-handbook-attendance',
    title: 'Attendance & Tardiness Policy',
    category: POLICY_DOCUMENT_CATEGORIES.HANDBOOK_POLICY,
    tag: 'Operations',
    body: 'Staff record campus attendance daily by 9:00 AM. Tardiness beyond 15 minutes requires a note to the office manager. Patterns of absence are reviewed monthly with the director.',
    steps: null,
    autismConsiderations: null,
  },
  {
    importHash: 'policy-doc-handbook-parent-comm',
    title: 'Parent Communication Standards',
    category: POLICY_DOCUMENT_CATEGORIES.HANDBOOK_POLICY,
    tag: 'Communication',
    body: 'Use plain, respectful language with families. Acknowledge messages within one business day. Document significant conversations in the communication log.',
    steps: null,
    autismConsiderations: null,
  },
  {
    importHash: 'policy-doc-handbook-prof-dev',
    title: 'Professional Development Requirements',
    category: POLICY_DOCUMENT_CATEGORIES.HANDBOOK_POLICY,
    tag: 'Professional Growth',
    body: 'All instructional staff complete 20 hours of professional development annually, including at least 6 hours on autism-specific practices and de-escalation.',
    steps: null,
    autismConsiderations: null,
  },
];

const ALL_ROWS = [...SAFETY_ROWS, ...HANDBOOK_ROWS];

interface SeedScope {
  readonly key: string;
  readonly organizationId: string;
  readonly schoolId: string | null;
  readonly campusId: string | null;
}

const PRIMARY_CAMPUS_IDS = [
  ...SEED_SCHOOL_CAMPUS_IDS[SEED_SCHOOL_ID],
  ...SEED_SCHOOL_CAMPUS_IDS[SEED_SCHOOL_2_ID],
];

const SEED_SCOPES: readonly SeedScope[] = [
  {
    key: 'demo-org',
    organizationId: SEED_ORGANIZATION_ID,
    schoolId: null,
    campusId: null,
  },
  {
    key: 'demo-school-north',
    organizationId: SEED_ORGANIZATION_ID,
    schoolId: SEED_SCHOOL_ID,
    campusId: null,
  },
  {
    key: 'demo-school-south',
    organizationId: SEED_ORGANIZATION_ID,
    schoolId: SEED_SCHOOL_2_ID,
    campusId: null,
  },
  ...PRIMARY_CAMPUS_IDS.map((campusId) => ({
    key: `demo-campus-${campusId}`,
    organizationId: SEED_ORGANIZATION_ID,
    schoolId: null,
    campusId,
  })),
  {
    key: 'rival-org',
    organizationId: SEED_ORGANIZATION_2_ID,
    schoolId: null,
    campusId: null,
  },
  {
    key: 'rival-school',
    organizationId: SEED_ORGANIZATION_2_ID,
    schoolId: SEED_SECONDARY_SCHOOL_ID,
    campusId: null,
  },
  {
    key: 'rival-campus',
    organizationId: SEED_ORGANIZATION_2_ID,
    schoolId: null,
    campusId: SEED_SECONDARY_CAMPUS_ID,
  },
];

function scopedImportHash(scope: SeedScope, row: SeedRow): string {
  return `${row.importHash}-${scope.key}`;
}

function getScopeDirector(scope: SeedScope) {
  const fixtureUsers = scope.organizationId === SEED_ORGANIZATION_2_ID
    ? SEED_SECONDARY_USERS
    : SEED_FIXTURE_USERS;

  return fixtureUsers.find((user) => user.role === ROLE_NAMES.DIRECTOR) ?? null;
}

export default {
  up: async (queryInterface: QueryInterface) => {
    const now = new Date();
    const importHashes = SEED_SCOPES.flatMap((scope) =>
      ALL_ROWS.map((row) => scopedImportHash(scope, row)),
    );

    const rows = SEED_SCOPES.flatMap((scope) => {
      const director = getScopeDirector(scope);
      const author = director
        ? formatPersonName(director.namePrefix, director.firstName, director.lastName)
        : null;
      const authorId = director?.id ?? null;

      return ALL_ROWS.map((row) => ({
        id: uuid(),
        title: row.title,
        body: row.body,
        category: row.category,
        tag: row.tag,
        author,
        // JSONB columns: serialize for bulkInsert (Postgres casts JSON → jsonb).
        steps: row.steps ? JSON.stringify(row.steps) : null,
        autism_considerations: row.autismConsiderations
          ? JSON.stringify(row.autismConsiderations)
          : null,
        version: 1,
        active: true,
        importHash: scopedImportHash(scope, row),
        organizationId: scope.organizationId,
        schoolId: scope.schoolId,
        campusId: scope.campusId,
        classId: null,
        createdById: authorId,
        updatedById: authorId,
        createdAt: now,
        updatedAt: now,
      }));
    });
    const existing = await queryInterface.sequelize.query<{ importHash: string }>(
      `SELECT "importHash" FROM policy_documents WHERE "importHash" IN (:importHashes)`,
      {
        replacements: { importHashes },
        type: QueryTypes.SELECT,
      },
    );
    const existingImportHashes = new Set(existing.map((row) => row.importHash));
    const missingRows = rows.filter(
      (row) => !existingImportHashes.has(row.importHash),
    );

    if (missingRows.length > 0) {
      await queryInterface.bulkInsert('policy_documents', missingRows);
    }
  },

  down: async (queryInterface: QueryInterface) => {
    await queryInterface.bulkDelete('policy_documents', {
      importHash: {
        [Op.in]: SEED_SCOPES.flatMap((scope) =>
          ALL_ROWS.map((row) => scopedImportHash(scope, row)),
        ),
      },
    });
  },
};
