import * as plugins from '../plugins.js';
import { Reception } from './classes.reception.js';
import { Organization } from './classes.organization.js';
import { User } from './classes.user.js';

export class OrganizationManager {
  public receptionRef: Reception;
  public get db() {
    return this.receptionRef.db.smartdataDb;
  }
  public typedrouter = new plugins.typedrequest.TypedRouter();

  public COrganization = plugins.smartdata.setDefaultManagerForDoc(this, Organization);

  constructor(receptionRefArg: Reception) {
    this.receptionRef = receptionRefArg;
    this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);

    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_CreateOrganization>(
        'createOrganization',
        async (requestArg) => {
          const nameIsAvailable = async () => {
            const existingOrg = await this.COrganization.getInstance({
              data: {
                slug: requestArg.organizationSlug,
              },
            });
            const nameAvailable = !existingOrg;
            return nameAvailable;
          };
          switch (requestArg.action) {
            case 'checkAvailability':
              return {
                nameAvailable: await nameIsAvailable(),
              };
              break;
            case 'manifest':
              const nameCheckedOk = await nameIsAvailable();
              const userData = await this.receptionRef.userManager.getUserByJwtValidation(
                requestArg.jwt
              );
              const newOrg = await this.COrganization.createNewOrganizationForUser(
                this,
                userData.id,
                requestArg.organizationName,
                requestArg.organizationSlug
              );
              const role = await this.receptionRef.roleManager.modifyRoleForUserAtOrg({
                action: 'create',
                organizationId: newOrg.id,
                userId: userData.id,
                role: 'admin',
              });
              newOrg.data.roleIds.push(role.id);
              await newOrg.save();
              return {
                nameAvailable: true,
                resultingOrganization: await newOrg.createSavableObject()
              }
              break;
          }
        }
      )
    );
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetOrganizationById>(
        'getOrganizationById',
        async (requestArg) => {
          const verifiedJwt = await this.receptionRef.jwtManager.verifyJWTAndGetData(
            requestArg.jwt
          );
          const user = await this.receptionRef.userManager.CUser.getInstance({
            id: verifiedJwt.data.userId,
          });
          const organization = await this.COrganization.getInstance({
            id: requestArg.id
          });
          const role = await this.receptionRef.roleManager.CRole.getInstance({
            data: {
              organizationId: organization.id,
              userId: user.id,
            }
          });

          if (!role) {
            throw new plugins.typedrequest.TypedResponseError('User not authorized for the requested organization.');
          }
          return {
            organization: await organization.createSavableObject()
          };
        }
      )
    );
  }

  public async getAllOrganizationsForUser(
    userArg: User,
  ) {
    
    const organizations: Organization[] = [];
    const userRoles = await this.receptionRef.roleManager.getAllRolesForUser(userArg);

    for (const role of userRoles) {
      const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({
        id: role.data.organizationId
      });
      if (!organizations.find(orgArg => orgArg.id === organization.id)) {
        organizations.push(organization);
      }
    }

    return organizations;
  }
}
