import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import { RoleAccessEntity } from './entities/role_access.entity';
import { UserEntity } from '../user/entities/user.entity';
import { ModuleEntity } from '../modules/entities/modules.entity';

@Injectable()
export class RoleAccessService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepo: Repository<UserEntity>,

    @InjectRepository(RoleAccessEntity)
    private readonly roleAccessRepo: Repository<RoleAccessEntity>,

    private readonly dataSource: DataSource,
  ) {}

  async createUserWithRoleAccess(data: any) {
    return await this.dataSource.transaction(async (manager) => {
      // 1️⃣ Create user (always in users table)
      const userInsert = await manager
        .createQueryBuilder()
        .insert()
        .into(UserEntity)
        .values({
          username: data.email,
          email: data.email,
          password: data.password,
          fullName: data.fullName,
          phone: data.phone || null,
          role: data.role, // dynamic role
          status: 'active',
        })
        .execute();

      const userId = userInsert.identifiers[0].id;

      // 2️⃣ If role is OPERATION → save role_access with multiple modules
      if (data.role === 'operation' && Array.isArray(data.moduleIds)) {
        for (const moduleId of data.moduleIds) {
          await manager
            .createQueryBuilder()
            .insert()
            .into(RoleAccessEntity)
            .values({
              userId,
              role: data.role,
              moduleId,
              status: 'active',
            })
            .execute();
        }
      }

      return {
        success: true,
        message: `${data.role} user created successfully`,
        userId,
      };
    });
  }

  // 🔹 Special update for OPERATION role
  async updateUserWithRoleAccess(id: number, data: any) {
    return await this.dataSource.transaction(async (manager) => {
      // 1️⃣ Update users table
      await manager
        .createQueryBuilder()
        .update(UserEntity)
        .set({
          username: data.username || data.email,
          email: data.email,
          password: data.password || undefined, // ⚠ no hashing (as per your request)
          fullName: data.fullName,
          phone: data.phone || null,
          role: data.role, // ✅ dynamic role
          status: data.status || 'active',
        })
        .where('id = :id', { id })
        .execute();

      // 2️⃣ Handle role_access based on role
      if (data.role === 'operation' && Array.isArray(data.moduleIds)) {
        // Delete old role_access
        await manager
          .createQueryBuilder()
          .delete()
          .from(RoleAccessEntity)
          .where('userId = :id', { id })
          .execute();

        // Insert new access
        for (const moduleId of data.moduleIds) {
          await manager
            .createQueryBuilder()
            .insert()
            .into(RoleAccessEntity)
            .values({
              userId: id,
              role: 'operation',
              moduleId,
              status: 'active',
            })
            .execute();
        }
      } else {
        // ❌ If role is NOT operation → clear any old role_access
        await manager
          .createQueryBuilder()
          .delete()
          .from(RoleAccessEntity)
          .where('userId = :id', { id })
          .execute();
      }

      return {
        success: true,
        message: `User updated successfully as ${data.role}`,
        userId: id,
      };
    });
  }

  async getModulesByUser(userId: number) {
    try {
      // Get all modules
      const allModules = await this.dataSource
        .getRepository(ModuleEntity)
        .find();

      // Get assigned modules for this user
      const assigned = await this.roleAccessRepo.find({
        where: { userId, status: 'active' },
        select: ['moduleId'],
      });

      const assignedIds = assigned.map((a) => a.moduleId);

      // Mark assigned ones
      return allModules.map((m) => ({
        id: m.id,
        name: m.name,
        keyName: m.keyName,
        description: m.description,
        status: m.status,
        assigned: assignedIds.includes(m.id), // ✅ flag for UI
      }));
    } catch (error) {
      throw new Error('Error fetching modules for user: ' + error.message);
    }
  }
}
