import { randomUUID } from 'node:crypto';
import pino from 'pino';
import { loadEnv } from '../../src/config/env.js';
import { createDatabase } from '../../src/db/database.js';
import { migrate } from '../../src/db/migrations.js';
import { createApplication, createHttpServer } from '../../src/http/app.js';
import { RealtimeHub } from '../../src/realtime/hub.js';
import { hashPassword } from '../../src/services/passwords.js';
import { seedDatabase } from '../../src/services/seed-data.js';

const testPassword = 'E2E-Strong-Password-123!';
Object.assign(process.env, {
  NODE_ENV: 'test', PORT: '3210', APP_URL: 'http://127.0.0.1:3210',
  APP_KEY: 'e2e-application-key-with-more-than-32-characters',
  SESSION_SECRET: 'e2e-session-secret-with-more-than-32-characters',
  DATABASE_DRIVER: 'pglite', PGLITE_DATA_DIR: 'storage/e2e-pglite',
  REDIS_REQUIRED: 'false', SECURE_COOKIES: 'false', SEED_DEMO_USERS: 'false'
});

export async function startTestServer(): Promise<() => Promise<void>> {
  const env = loadEnv();
  const db = await createDatabase(env);
  await migrate(db);
  await seedDatabase(db, false);
  const branch = await db.query<{ id: string }>("SELECT id FROM branches WHERE code = 'MAIN'");
  const warehouse = await db.query<{ id: string }>("SELECT id FROM warehouses WHERE code = 'MAIN-WH'");
  const passwordHash = await hashPassword(testPassword);
  const users = [
    { username: 'e2e-admin', name: 'مدیر کل آزمون', role: 'super_admin', warehouseId: null },
    { username: 'e2e-supply', name: 'مدیر تأمین آزمون', role: 'supply_manager', warehouseId: null },
    { username: 'e2e-warehouse', name: 'انباردار آزمون', role: 'warehouse_operator', warehouseId: warehouse.rows[0]!.id }
  ];
  for (const user of users) {
    const existing = await db.query<{ id: string }>('SELECT id FROM users WHERE username_normalized = $1', [user.username]);
    const id = existing.rows[0]?.id ?? randomUUID();
    if (existing.rowCount) {
      await db.query(
        `UPDATE users SET name=$1, password_hash=$2, warehouse_id=$3, active=true, archived_at=NULL,
         force_password_change=false, session_version=session_version+1, updated_at=now() WHERE id=$4`,
        [user.name, passwordHash, user.warehouseId, id]
      );
      await db.query('DELETE FROM user_roles WHERE user_id = $1', [id]);
    } else {
      await db.query(
        `INSERT INTO users(id, branch_id, warehouse_id, name, username, username_normalized, password_hash, force_password_change)
         VALUES ($1,$2,$3,$4,$5,$5,$6,false)`,
        [id, branch.rows[0]!.id, user.warehouseId, user.name, user.username, passwordHash]
      );
    }
    await db.query(
      'INSERT INTO user_roles(user_id, role_id) SELECT $1, id FROM roles WHERE code=$2 ON CONFLICT DO NOTHING',
      [id, user.role]
    );
  }
  const realtime = new RealtimeHub(db, env);
  const server = createHttpServer(createApplication({ db, env, realtime, logger: pino({ level: 'silent' }) }), realtime);
  await new Promise<void>((resolve, reject) => {
    server.once('error', reject);
    server.listen(env.PORT, '127.0.0.1', resolve);
  });
  return async () => {
    await new Promise<void>((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
    await realtime.close();
    await db.close();
  };
}
