import { Injectable, Logger } from '@nestjs/common';
import { hashPassword } from '@tria-plc/api-common/utils/argon';
import { EUserStatus } from '@tria-plc/api-common/utils/enums/user.enum';
import {
  Employee,
  EmployeePosition,
  Organization,
  Position,
  Role,
  Unit,
  User,
  UserCredential,
  UserRole,
} from '@tria-plc/iamapi-common';
import { DataSource } from 'typeorm';

const SEED_FLAG = 'SEED_FREIGHT_STAFF';
const EDR_ORG_KEY = 'edr_freight';
const EDR_UNIT_KEY = 'edr_freight_app';

// roleKey is kept only for backwards compatibility with existing UserRole rows;
// access is granted via the assigned position (positionKey) + PositionPermission.
const STAFF_USERS = [
  { email: 'linestaff@edr.local', username: 'linestaff', roleKey: 'edr_line_staff', positionKey: 'operation' },
  { email: 'chief@edr.local', username: 'chief', roleKey: 'edr_org_manager', positionKey: 'chief' },
  { email: 'director@edr.local', username: 'director', roleKey: 'edr_director', positionKey: 'director' },
  { email: 'ceo@edr.local', username: 'ceo', roleKey: 'edr_ceo', positionKey: 'ceo' },
  { email: 'marketer@edr.local', username: 'marketer', roleKey: 'edr_marketing', positionKey: 'marketer' },
  { email: 'operation@edr.local', username: 'operation', roleKey: 'edr_operations_officer', positionKey: 'operation' },
  { email: 'gl-et@edr.local', username: 'gl_et', roleKey: 'edr_gl_ethiopia', positionKey: 'ethiopian_gl' },
  { email: 'gl-dj@edr.local', username: 'gl_dj', roleKey: 'edr_gl_djibouti', positionKey: 'djibouti_gl' },
] as const;

@Injectable()
export class FreightStaffUsersSeeder {
  private readonly logger = new Logger(FreightStaffUsersSeeder.name);

  constructor(private readonly dataSource: DataSource) {}

  async run() {
    if (process.env[SEED_FLAG]?.trim().toLowerCase() !== 'true') {
      this.logger.log(`Skipping freight staff seed because ${SEED_FLAG} is not enabled`);
      return;
    }

    const password =
      process.env.DEFAULT_PASSWORD?.trim() || '12345678';

    await this.dataSource.transaction(async (manager) => {
      const organization = await manager.getRepository(Organization).findOne({
        where: { key: EDR_ORG_KEY },
        select: { id: true, key: true },
      });

      if (!organization) {
        throw new Error(`missing_organization:${EDR_ORG_KEY}`);
      }

      const unit = await manager.getRepository(Unit).findOne({
        where: { key: EDR_UNIT_KEY, organizationId: organization.id },
        select: { id: true },
      });

      if (!unit) {
        throw new Error(`missing_unit:${EDR_UNIT_KEY}`);
      }

      const roleRepository = manager.getRepository(Role);
      const userRepository = manager.getRepository(User);
      const userCredentialRepository = manager.getRepository(UserCredential);
      const userRoleRepository = manager.getRepository(UserRole);
      const employeeRepository = manager.getRepository(Employee);
      const positionRepository = manager.getRepository(Position);
      const employeePositionRepository = manager.getRepository(EmployeePosition);

      const hashedPassword = await hashPassword(password);

      for (const staff of STAFF_USERS) {
        const role = await roleRepository.findOne({
          where: { key: staff.roleKey },
          select: { id: true, key: true },
        });

        if (!role) {
          throw new Error(`missing_role:${staff.roleKey}`);
        }

        let user = await userRepository.findOne({
          where: { email: staff.email },
          select: { id: true, email: true },
        });

        if (!user) {
          user = await userRepository.save(
            userRepository.create({
              email: staff.email,
              username: staff.username,
              name: { en: staff.username },
              isActive: true,
              hasSetPassword: true,
              status: EUserStatus.ACCEPTED,
            }),
          );
          this.logger.log(`Seeded freight staff user ${staff.email}`);
        }

        const activeCredentialExists = await userCredentialRepository.exists({
          where: { userId: user.id, isActive: true },
        });

        if (!activeCredentialExists) {
          await userCredentialRepository.insert({
            userId: user.id,
            password: hashedPassword,
            isActive: true,
          });
        }

        await userRoleRepository.upsert(
          {
            userId: user.id,
            roleId: role.id,
            organizationId: organization.id,
          },
          { conflictPaths: { userId: true, roleId: true } },
        );

        let employee = await employeeRepository.findOne({
          where: {
            userId: user.id,
            organizationId: organization.id,
            isCurrent: true,
          },
          select: { id: true },
        });

        if (!employee) {
          employee = await employeeRepository.save(
            employeeRepository.create({
              userId: user.id,
              organizationId: organization.id,
              unitId: unit.id,
              isCurrent: true,
              name: { en: staff.username },
            }),
          );
        }

        // Grant access via the assigned position (positions-as-roles).
        const position = await positionRepository.findOne({
          where: { key: staff.positionKey, unitId: unit.id },
          select: { id: true, key: true },
        });

        if (!position) {
          throw new Error(`missing_position:${staff.positionKey}`);
        }

        const employeePositionExists = await employeePositionRepository.exists({
          where: {
            employeeId: employee.id as string,
            positionId: position.id as string,
          },
        });

        if (!employeePositionExists) {
          await employeePositionRepository.insert({
            employeeId: employee.id as string,
            positionId: position.id as string,
            unitId: unit.id,
            isCurrent: true,
          });
        }
      }
    });

    this.logger.log(
      'Ensured freight staff users (linestaff@, director@, ceo@, gl@)',
    );
  }
}
