import EmployeesList from "../Models/Employees/Employee";
import { EmployeeRoles } from "../Models/Employees/Employees.Interface";
import UserList from "../Models/Users/Users";
import { IUserDocument } from "../Models/Users/Users.Adapter.Mongoose";
import { NoPermissionMessage } from "./NoPermissionMessage";
import CompaniesList from "../Models/Companies/Companies";
import { ICompanyDocument } from "../Models/Companies/Companies.Adapter.Mongoose";
import ClientsList from "../Models/Clients/Clients";
import { PlanFeatures } from "../Models/Plans/Plans.interface";
import PlanSubscriptionsList from "../Models/PlanSubscriptions/PlanSubscriptons";
import { IClientDocument } from "../Models/Clients/Clients.Adapter.Mongoose";

export type ValidateSessionUserParams = {
    sessionUser: string;
};

export type ValidateSessionUserResult = {
    user: IUserDocument;
};

export async function validateSessionUser(
    data: ValidateSessionUserParams
): Promise<ValidateSessionUserResult> {
    const sessionUser = await UserList.users.findOne({
        _id: data.sessionUser,
    });

    if (!sessionUser) {
        throw new Error(
            "No se ha encontrado el usuario o no tiene permisos para realizar esta acción"
        );
    }

    return { user: sessionUser };
}

export type ValidatePermissionsByCompanyParams = {
    companyId: string;
    sessionUser: string;
};

export type ValidatePermissionsByCompanyResult = {
    company: ICompanyDocument;
};

export async function validatePermissionsByCompany(
    data: ValidatePermissionsByCompanyParams
): Promise<ValidatePermissionsByCompanyResult> {
    const company = await CompaniesList.companies.findOne({
        _id: data.companyId,
    });

    if (!company) {
        throw new Error("No se ha encontrado la organización");
    }

    const hasAdminPermission = await EmployeesList.checkRoleById(
        data.companyId,
        data.sessionUser,
        EmployeeRoles.ADMIN
    );

    if (!hasAdminPermission) {
        throw new Error(NoPermissionMessage());
    }

    return { company };
}

export type ValidatePermissionsByClientParams = {
    sessionUser: string;
    feature?: PlanFeatures;
    clientId: string;
};

export type ValidationPermissionsByClientResult = {
    client: IClientDocument;
    company: ICompanyDocument;
};

export async function validatePermissionsByClient(
    data: ValidatePermissionsByClientParams
): Promise<ValidationPermissionsByClientResult> {
    const client = await ClientsList.clients.findOne({ _id: data.clientId });

    if (!client) {
        throw new Error("No se ha encontrado el cliente");
    }

    const clientCompany = await CompaniesList.companies.findOne({
        _id: String(client.companyId),
    });

    if (!clientCompany) {
        throw new Error("No se ha encontrado la empresa del cliente");
    }

    // Verificar si el usuario de sesión es un empleado con permisos de administrador
    const hasAdminPermission = await EmployeesList.checkRoleById(
        clientCompany.id,
        data.sessionUser,
        EmployeeRoles.ADMIN
    );

    if (!hasAdminPermission) {
        throw new Error(NoPermissionMessage());
    }

    if (data.feature) {
        const canAccess = await PlanSubscriptionsList.checkFeature({
            userId: String(clientCompany.ownerId),
            feature: data.feature,
        });

        if (!canAccess) {
            throw new Error("La organizacion no tiene un plan que soporte el módulo de pagos");
        }
    }

    return { client, company: clientCompany };
}

export type GetAuthorizedUsersParams = {
    companyId: string;
};

export type GetAuthorizedUsersResult = {
    companyId: string;
    authorizedUsers: string[];
};

export async function getAuthorizedUsers(
    data: GetAuthorizedUsersParams
): Promise<GetAuthorizedUsersResult> {
    const company = await CompaniesList.companies.findOne({
        _id: data.companyId,
    });

    if (!company) {
        throw new Error("No se ha encontrado la organización");
    }

    const employees = await EmployeesList.findByCompanyId({
        companyId: data.companyId,
    });

    let returnValue: string[] = [];

    for (const employee of employees) {
        const hasAdminPermission = await EmployeesList.checkRoleById(
            data.companyId,
            String(employee.userId),
            EmployeeRoles.ADMIN
        );

        if (hasAdminPermission) {
            returnValue.push(String(employee.userId));
        }
    }

    return {
        companyId: company.id,
        authorizedUsers: returnValue,
    };
}
