'use server';

import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';

import { enhanceAction } from '@kit/next/actions';
import { getLogger } from '@kit/shared/logger';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
import { getSupabaseServerClient } from '@kit/supabase/server-client';

import {
  BanUserSchema,
  DeleteAccountSchema,
  DeleteUserSchema,
  ImpersonateUserSchema,
  ReactivateUserSchema,
  UpdateAccountRoleSchema,
} from './schema/admin-actions.schema';
import { CreateCompanySchema } from './schema/create-company.schema';
import { CreateUserSchema } from './schema/create-user.schema';
import { ResetPasswordSchema } from './schema/reset-password.schema';
import { createAdminAccountsService } from './services/admin-accounts.service';
import { createAdminAuthUserService } from './services/admin-auth-user.service';
import { createCreateCompanyAccountService } from './services/admin-create-company-account.service';
import { adminAction } from './utils/admin-action';
import { getAdminSdk } from './utils/medusa-sdk';

/**
 * @name banUserAction
 * @description Ban a user from the system.
 */
export const banUserAction = adminAction(
  enhanceAction(
    async ({ userId }) => {
      const service = getAdminAuthService();
      const logger = await getLogger();

      logger.info({ userId }, `Super Admin is banning user...`);

      await service.banUser(userId);

      logger.info({ userId }, `Super Admin has successfully banned user`);

      revalidateAdmin();

      return {
        success: true,
      };
    },
    {
      schema: BanUserSchema,
    },
  ),
);

/**
 * @name reactivateUserAction
 * @description Reactivate a user in the system.
 */
export const reactivateUserAction = adminAction(
  enhanceAction(
    async ({ userId }) => {
      const service = getAdminAuthService();
      const logger = await getLogger();

      logger.info({ userId }, `Super Admin is reactivating user...`);

      await service.reactivateUser(userId);

      logger.info({ userId }, `Super Admin has successfully reactivated user`);

      revalidateAdmin();

      return {
        success: true,
      };
    },
    {
      schema: ReactivateUserSchema,
    },
  ),
);

/**
 * @name impersonateUserAction
 * @description Impersonate a user in the system.
 */
export const impersonateUserAction = adminAction(
  enhanceAction(
    async ({ userId }) => {
      const service = getAdminAuthService();
      const logger = await getLogger();

      logger.info({ userId }, `Super Admin is impersonating user...`);

      return await service.impersonateUser(userId);
    },
    {
      schema: ImpersonateUserSchema,
    },
  ),
);

/**
 * @name deleteUserAction
 * @description Delete a user from the system.
 */
export const deleteUserAction = adminAction(
  enhanceAction(
    async ({ userId }) => {
      const service = getAdminAuthService();
      const logger = await getLogger();

      logger.info({ userId }, `Super Admin is deleting user...`);

      await service.deleteUser(userId);

      logger.info({ userId }, `Super Admin has successfully deleted user`);

      revalidateAdmin();

      return redirect('/admin/accounts');
    },
    {
      schema: DeleteUserSchema,
    },
  ),
);

/**
 * @name deleteAccountAction
 * @description Delete an account from the system.
 */
export const deleteAccountAction = adminAction(
  enhanceAction(
    async ({ accountId }) => {
      const service = getAdminAccountsService();
      const logger = await getLogger();

      logger.info({ accountId }, `Super Admin is deleting account...`);

      const { name: customerGroupName } = await service.getAccount(accountId);
      try {
        await service.deleteAccount(accountId);
      } catch (e) {
        logger.error({ accountId }, `Error deleting company account`);
        throw e;
      }
      const medusa = getAdminSdk();
      const { customer_groups } = await medusa.admin.customerGroup.list();
      const customerGroup = customer_groups.find(
        ({ name }) => name === customerGroupName,
      );
      if (customerGroup) {
        try {
          await medusa.admin.customerGroup.delete(customerGroup.id);
        } catch (e) {
          logger.error(
            { accountId },
            `Error deleting Medusa customer group for company ${customerGroupName}`,
          );
          throw e;
        }
      }

      logger.info(
        { accountId },
        `Super Admin has successfully deleted account`,
      );

      revalidateAdmin();

      return redirect('/admin/accounts');
    },
    {
      schema: DeleteAccountSchema,
    },
  ),
);

/**
 * @name createUserAction
 * @description Create a new user in the system.
 */
export const createUserAction = adminAction(
  enhanceAction(
    async ({ email, password, emailConfirm, personalCode }) => {
      const adminClient = getSupabaseServerAdminClient();
      const logger = await getLogger();

      logger.info({ email }, `Super Admin is creating a new user...`);

      const { data, error } = await adminClient.auth.admin.createUser({
        email,
        password,
        email_confirm: emailConfirm,
      });

      if (error) {
        logger.error({ error }, `Error creating user`);
        throw new Error(`Error creating user: ${error.message}`);
      }

      logger.info(
        { userId: data.user.id },
        `Super Admin has successfully created a new user`,
      );

      const { error: accountError } = await adminClient
        .schema('medreport')
        .from('accounts')
        .update({ personal_code: personalCode })
        .eq('id', data.user.id);

      if (accountError) {
        logger.error(
          { accountError },
          'Error inserting personal code to accounts',
        );
        throw new Error(`Error saving personal code: ${accountError.message}`);
      }

      revalidateAdmin();

      return {
        success: true,
        user: data.user,
      };
    },
    {
      schema: CreateUserSchema,
    },
  ),
);

/**
 * @name resetPasswordAction
 * @description Reset a user's password by sending a password reset email.
 */
export const resetPasswordAction = adminAction(
  enhanceAction(
    async ({ userId }) => {
      const service = getAdminAuthService();
      const logger = await getLogger();

      logger.info({ userId }, `Super Admin is resetting user password...`);

      const result = await service.resetPassword(userId);

      logger.info(
        { userId },
        `Super Admin has successfully sent password reset email`,
      );

      revalidateAdmin();

      return result;
    },
    {
      schema: ResetPasswordSchema,
    },
  ),
);

export const createCompanyAccountAction = enhanceAction(
  async ({ name, ownerPersonalCode }, user) => {
    const logger = await getLogger();
    const client = getSupabaseServerClient();
    const service = createCreateCompanyAccountService(client);

    const ctx = {
      name: 'team-accounts.create',
      userId: user.id,
      accountName: name,
    };

    logger.info(ctx, `Creating company account...`);

    const { data, error } = await service.createNewOrganizationAccount({
      name,
      ownerPersonalCode,
    });

    if (error) {
      logger.error({ ...ctx, error }, `Failed to create company account`);

      return {
        error: true,
      };
    }

    logger.info(ctx, `Company account created`);

    logger.info(ctx, `Creating Medusa customer group`);
    const medusa = getAdminSdk();
    const { customer_groups: existingCustomerGroups } =
      await medusa.admin.customerGroup.list();
    const isExisting = existingCustomerGroups.find(
      (group) => group.name === name,
    );
    if (isExisting) {
      logger.info(ctx, `Customer group already exists`);
    } else {
      logger.info(ctx, `Creating Medusa customer group`);
      const { data: account } = await client
        .schema('medreport')
        .from('accounts')
        .select('medusa_account_id')
        .eq('personal_code', ownerPersonalCode)
        .single()
        .throwOnError();
      const medusaAccountId = account.medusa_account_id;
      if (!medusaAccountId) {
        logger.error(ctx, `User has no Medusa account ID`);
      } else {
        const {
          customer_group: { id: customerGroupId },
        } = await medusa.admin.customerGroup.create({ name });
        const { customers } = await medusa.admin.customer.list({
          id: medusaAccountId,
        });
        if (customers.length !== 1) {
          logger.error(ctx, `Customer not found`);
        } else {
          const customerId = customers[0]!.id;
          await medusa.admin.customer.batchCustomerGroups(customerId, {
            add: [customerGroupId],
          });
        }
      }
    }

    redirect(`/admin/accounts/${data.id}`);
  },
  {
    schema: CreateCompanySchema,
  },
);

/**
 * @name updateRoleAction
 * @description Update application role for user
 */
export const updateRoleAction = adminAction(
  enhanceAction(
    async ({ accountId, role }) => {
      const service = getAdminAccountsService();
      const logger = await getLogger();

      logger.info({ accountId }, `Super Admin is updating account role...`);

      await service.updateRole(accountId, role);

      logger.info({ accountId }, `Successfully changed role`);

      revalidateAdmin();

      return { success: true };
    },
    {
      schema: UpdateAccountRoleSchema,
    },
  ),
);

function revalidateAdmin() {
  revalidatePath('/admin', 'layout');
}

function getAdminAuthService() {
  const client = getSupabaseServerClient();
  const adminClient = getSupabaseServerAdminClient();

  return createAdminAuthUserService(client, adminClient);
}

function getAdminAccountsService() {
  const adminClient = getSupabaseServerAdminClient();

  return createAdminAccountsService(adminClient);
}
