import { Sequelize } from 'sequelize';
import dbConfig from '@/db/db.config';
import {
  DEFAULT_DEV_DB_HOST,
  DEFAULT_DEV_DB_NAME,
  DEFAULT_DEV_DB_PASS,
  DEFAULT_DEV_DB_USER,
} from '@/shared/constants/app';

import academic_years from './academic_years';
import assessment_results from './assessment_results';
import assessments from './assessments';
import audio_files from './audio_files';
import attendance_records from './attendance_records';
import attendance_sessions from './attendance_sessions';
import auth_refresh_tokens from './auth_refresh_tokens';
import campus_attendance_config from './campus_attendance_config';
import campus_attendance_summaries from './campus_attendance_summaries';
import campuses from './campuses';
import class_enrollments from './class_enrollments';
import class_subjects from './class_subjects';
import classes from './classes';
import communication_events from './communication_events';
import content_catalog from './content_catalog';
import file from './file';
import frame_entries from './frame_entries';
import grades from './grades';
import message_recipients from './message_recipients';
import messages from './messages';
import organizations from './organizations';
import permissions from './permissions';
import personality_quiz_results from './personality_quiz_results';
import policy_acknowledgments from './policy_acknowledgments';
import policy_documents from './policy_documents';
import roles from './roles';
import safety_quiz_results from './safety_quiz_results';
import staff from './staff';
import staff_attendance_records from './staff_attendance_records';
import subjects from './subjects';
import timetable_periods from './timetable_periods';
import timetables from './timetables';
import user_progress from './user_progress';
import walkthrough_checkins from './walkthrough_checkins';
import users from './users';

const env = process.env.NODE_ENV || 'development';
const isProductionLike = env === 'production' || env === 'dev_stage';

function selectConnection(): {
  database?: string;
  username?: string;
  password?: string;
  host?: string;
  port?: string;
} {
  if (env === 'production') {
    return dbConfig.production;
  }

  if (env === 'dev_stage') {
    return dbConfig.dev_stage;
  }

  return dbConfig.development;
}

/**
 * Validates that all required DB credentials are set in production-like environments.
 * Dev defaults must never be used in production.
 */
function validateProductionDbConfig(connection: ReturnType<typeof selectConnection>): void {
  if (!isProductionLike) {
    return;
  }

  const missing: string[] = [];
  if (!connection.database) missing.push('DB_NAME');
  if (!connection.username) missing.push('DB_USER');
  if (!connection.password) missing.push('DB_PASS');
  if (!connection.host) missing.push('DB_HOST');

  if (missing.length > 0) {
    throw new Error(
      `Missing required database credentials in ${env}: ${missing.join(', ')} (no dev defaults allowed)`,
    );
  }
}

const connection = selectConnection();
validateProductionDbConfig(connection);

const sequelize = new Sequelize(
  connection.database ?? DEFAULT_DEV_DB_NAME,
  connection.username ?? DEFAULT_DEV_DB_USER,
  connection.password ?? DEFAULT_DEV_DB_PASS,
  {
    dialect: 'postgres',
    host: connection.host ?? DEFAULT_DEV_DB_HOST,
    port: connection.port ? Number(connection.port) : undefined,
    logging: console.log,
  },
);

const models = {
  academic_years: academic_years(sequelize),
  assessment_results: assessment_results(sequelize),
  assessments: assessments(sequelize),
  audio_files: audio_files(sequelize),
  attendance_records: attendance_records(sequelize),
  attendance_sessions: attendance_sessions(sequelize),
  auth_refresh_tokens: auth_refresh_tokens(sequelize),
  campus_attendance_config: campus_attendance_config(sequelize),
  campus_attendance_summaries: campus_attendance_summaries(sequelize),
  campuses: campuses(sequelize),
  class_enrollments: class_enrollments(sequelize),
  class_subjects: class_subjects(sequelize),
  classes: classes(sequelize),
  communication_events: communication_events(sequelize),
  content_catalog: content_catalog(sequelize),
  file: file(sequelize),
  frame_entries: frame_entries(sequelize),
  grades: grades(sequelize),
  message_recipients: message_recipients(sequelize),
  messages: messages(sequelize),
  organizations: organizations(sequelize),
  permissions: permissions(sequelize),
  personality_quiz_results: personality_quiz_results(sequelize),
  policy_acknowledgments: policy_acknowledgments(sequelize),
  policy_documents: policy_documents(sequelize),
  roles: roles(sequelize),
  safety_quiz_results: safety_quiz_results(sequelize),
  staff: staff(sequelize),
  staff_attendance_records: staff_attendance_records(sequelize),
  subjects: subjects(sequelize),
  timetable_periods: timetable_periods(sequelize),
  timetables: timetables(sequelize),
  user_progress: user_progress(sequelize),
  walkthrough_checkins: walkthrough_checkins(sequelize),
  users: users(sequelize),
};

for (const model of Object.values(models)) {
  model.associate?.(models);
}

const db = {
  ...models,
  sequelize,
  Sequelize,
};

export default db;
