import Login from '../models/login.js';
import Client from '../models/client.js';
import Treelogy from '../models/treelogy.js';
import Mapping from '../models/mapping.js';
import UserMaster from '../models/userMaster.js';
import { successResponse, errorResponse } from '../utils/response.js';
import bcrypt from 'bcryptjs';
import { getRoleNames } from '../middleware/auth.js';

export async function createLogin(req, res) {
  try {
    const {
      treelogy_id, security_no = '0', com_id, client_id,
      member_id, mobile_number = '0', password,
      authority, name, status = 'Y'
    } = req.body;

    // Get role names dynamically
    const roleNames = await getRoleNames();
    const SUPER_ADMIN = roleNames.find(name => name === 'SUPER_ADMIN');
    const CLIENT_ADMIN = roleNames.find(name => name === 'CLIENT_ADMIN');
    const PROJECT_USER = roleNames.find(name => name === 'PROJECT_USER');

    const isSA = req.user?.role_name === SUPER_ADMIN;

    // Determine role_id based on authority (role_name) from request
    let role_id;
    if (authority) {
      // Find role by role_name provided in authority field
      const role = await UserMaster.findOne({ where: { role_name: authority } });
      if (!role) {
        return errorResponse(res, `Role '${authority}' not found in database`, 400);
      }
      role_id = role.id;
    } else {
      // Default to PROJECT_USER if no authority specified
      const role = await UserMaster.findOne({ where: { role_name: 'PROJECT_USER' } });
      if (!role) {
        return errorResponse(res, 'PROJECT_USER role not found in database', 500);
      }
      role_id = role.id;
    }

    if (!isSA) {
      // For CLIENT_ADMIN, ensure they can only create users under their own client
      if (req.user?.role_name === CLIENT_ADMIN) {
        if (!member_id || !password || !name) {
          return errorResponse(res, 'Missing required fields', 400);
        }

        // CLIENT_ADMIN can only create users for their own client
        if (req.user?.client_id !== client_id) {
          return errorResponse(res, 'You can only create users under your own client', 403);
        }
      } else {
        return errorResponse(res, 'Forbidden', 403);
      }
    } else {
      // SUPER_ADMIN can create users with any role
      if (!member_id || !password || !name) {
        return errorResponse(res, 'Missing required fields', 400);
      }
    }

    // Validate client if provided
    if (client_id) {
      const client = await Client.findByPk(client_id);
      if (!client) return errorResponse(res, 'Client not found', 404);
    }

    if (treelogy_id) {
      const tree = await Treelogy.findByPk(treelogy_id);
      if (!tree) return errorResponse(res, 'Project not found', 404);
    }

    // Check if member_id already exists (now must be unique across system)
    const existingMemberId = await Login.findOne({ where: { member_id } });
    if (existingMemberId) {
      return errorResponse(res, `Member ID '${member_id}' is already taken. Please choose a different member ID.`, 409);
    }

    const hash = await bcrypt.hash(password, 10);

    const login = await Login.create({
      treelogy_id,
      security_no,
      com_id,
      client_id: client_id || req.user?.client_id, // Use user's client_id if not provided
      member_id,
      mobile_number,
      password: hash,
      role_id, // Use role_id instead of authority
      name,
      status
    });

    // If user has a treelogy_id, create a mapping entry for PROJECT_USER roles
    if (treelogy_id && role_id) {
      const role = await UserMaster.findByPk(role_id);
      if (role && role.role_name === 'PROJECT_USER') {
        const Mapping = (await import('../models/mapping.js')).default;
        await Mapping.create({
          login_id: login.login_id,
          treelogy_id: treelogy_id,
          description: `${name} - ${member_id}`,
          code: `${member_id}-${treelogy_id}`,
          role: 'USER',
          view_permission: 'FULL',
          profile: 0,
          status: 1,
          created_by: req.user?.login_id || 0,
          sort_order: 0,
          current_map_year: new Date().getFullYear()
        });
      }
    }

    return successResponse(res, 201, 'User created successfully', {
      ...login.toJSON(),
      password: undefined
    });
  } catch (error) {
    console.error('Error creating user:', error);
    // Check if it's a unique constraint violation
    if (error.name === 'SequelizeUniqueConstraintError') {
      return errorResponse(res, `Member ID '${req.body.member_id}' is already taken. Please choose a different member ID.`, 409);
    }
    return errorResponse(res, 'Error creating user', 500, error.message);
  }
}

export async function getLoginByClient(req, res) {
  try {
    const { client_id } = req.params;
    const logins = await Login.findAll({
      where: { client_id },
      include: [
        { model: Client, foreignKey: 'client_id' },
        { model: Treelogy, foreignKey: 'treelogy_id' },
        { model: Mapping, foreignKey: 'login_id' },
        { model: UserMaster, foreignKey: 'role_id' },
      ]
    });
    return successResponse(res, 200, 'Users fetched successfully', logins);
  } catch (error) {
    return errorResponse(res, 'Error fetching users', 500, error.message);
  }
}

export async function updateLogin(req, res) {
  try {
    // Get data from the request body
    const {
      treelogy_id, security_no, com_id, client_id,
      member_id, mobile_number, password,
      authority, name, status
    } = req.body;

    // Ensure the user ID exists for update (using member_id in the URL or body)
    const userMemberId = req.params.member_id || member_id; // Use member_id from body if URL doesn't provide it

    if (!userMemberId) {
      return errorResponse(res, 'Member ID is required for update', 400);
    }

    const userToUpdate = await Login.findOne({ where: { member_id: userMemberId } });
    if (!userToUpdate) {
      return errorResponse(res, `User with member ID '${userMemberId}' not found.`, 404);
    }

    // Get role names dynamically
    const roleNames = await getRoleNames();
    const SUPER_ADMIN = roleNames.find(name => name === 'SUPER_ADMIN');
    const CLIENT_ADMIN = roleNames.find(name => name === 'CLIENT_ADMIN');
    const PROJECT_USER = roleNames.find(name => name === 'PROJECT_USER');

    const isSA = req.user?.role_name === SUPER_ADMIN;

    // Determine role_id based on authority (role_name) from request
    let role_id;
    if (authority) {
      // Find role by role_name provided in authority field
      const role = await UserMaster.findOne({ where: { role_name: authority } });
      if (!role) {
        return errorResponse(res, `Role '${authority}' not found in database`, 400);
      }
      role_id = role.id;
    } else {
      // Default to PROJECT_USER if no authority specified
      const role = await UserMaster.findOne({ where: { role_name: 'PROJECT_USER' } });
      if (!role) {
        return errorResponse(res, 'PROJECT_USER role not found in database', 500);
      }
      role_id = role.id;
    }

    if (!isSA) {
      // For CLIENT_ADMIN, ensure they can only update users under their own client
      if (req.user?.role_name === CLIENT_ADMIN) {
        if (req.user?.client_id !== client_id) {
          return errorResponse(res, 'You can only update users under your own client', 403);
        }
      } else {
        return errorResponse(res, 'Forbidden', 403);
      }
    } else {
      // SUPER_ADMIN can update users with any role
      if (!member_id && !password && !name) {
        return errorResponse(res, 'Missing required fields to update', 400);
      }
    }

    // Validate client if provided
    if (client_id) {
      const client = await Client.findByPk(client_id);
      if (!client) return errorResponse(res, 'Client not found', 404);
    }

    if (treelogy_id) {
      const tree = await Treelogy.findByPk(treelogy_id);
      if (!tree) return errorResponse(res, 'Project not found', 404);
    }

    // Only check for member_id uniqueness if it's being updated (it must be different from current member_id)
    if (member_id && member_id !== userMemberId) {
      const existingMemberId = await Login.findOne({ where: { member_id } });
      if (existingMemberId) {
        return errorResponse(res, `Member ID '${member_id}' is already taken. Please choose a different member ID.`, 409);
      }
    }

    // Prepare the data to be updated
    const updatedData = {};

    if (mobile_number) updatedData.mobile_number = mobile_number;
    if (password) updatedData.password = await bcrypt.hash(password, 10); // If password is provided, hash it
    if (name) updatedData.name = name;
    if (status) updatedData.status = status;
    if (treelogy_id) updatedData.treelogy_id = treelogy_id;
    if (security_no) updatedData.security_no = security_no;
    if (com_id) updatedData.com_id = com_id;
    if (client_id) updatedData.client_id = client_id;
    if (role_id) updatedData.role_id = role_id;

    // Update the user with only the changed fields
    const updatedUser = await userToUpdate.update(updatedData);

    return successResponse(res, 200, 'User updated successfully', {
      ...updatedUser.toJSON(),
      password: undefined // Don't return the password in the response
    });

  } catch (error) {
    console.error('Error updating user:', error);
    // Check if it's a unique constraint violation
    if (error.name === 'SequelizeUniqueConstraintError') {
      return errorResponse(res, `Member ID '${req.body.member_id}' is already taken. Please choose a different member ID.`, 409);
    }
    return errorResponse(res, 'Error updating user', 500, error.message);
  }
}




