import { Prisma } from '@prisma/client';
import { prisma } from '../../config/database';
import { logger } from '../../utils/logger';
import { vaultwardenClient } from '../vaultwarden.client';
import type { ServiceProvisioner, ProvisionerConfig, ProvisionResult, CMUser } from './provisioner.interface';

const ROLE_MAP: Record<string, string[]> = {
  SUPER_ADMIN: ['admin'],
  INFLUENCE_ADMIN: ['user'],
  MAP_ADMIN: ['user'],
  USER: ['user'],
  TEMP: [],
};

class VaultwardenProvisioner implements ServiceProvisioner {
  readonly config: ProvisionerConfig = {
    serviceKey: 'vaultwarden',
    displayName: 'Vaultwarden',
    featureFlag: 'provisionVaultwarden',
    permissionsKey: '_vaultwardenUserId',
    roleMap: ROLE_MAP,
    excludeRoles: ['TEMP'],
  };

  async isAvailable(): Promise<boolean> {
    return vaultwardenClient.healthCheck();
  }

  async provision(user: CMUser): Promise<ProvisionResult> {
    try {
      // Check if user already exists in Vaultwarden
      let vwUser = await vaultwardenClient.findUserByEmail(user.email);

      if (!vwUser) {
        // Invite-based: Vaultwarden sends email, user sets own master password
        await vaultwardenClient.inviteUser(user.email);
        logger.info(`Vaultwarden provisioner: invited ${user.email}`);

        // Try to find the newly created user (invite creates a pending user)
        vwUser = await vaultwardenClient.findUserByEmail(user.email);
      }

      const vwUserId = vwUser?.Id || null;
      const now = new Date().toISOString();

      // Persist Vaultwarden info in permissions
      const permissions = (user.permissions as Record<string, unknown>) || {};
      await prisma.user.update({
        where: { id: user.id },
        data: {
          permissions: {
            ...permissions,
            [this.config.permissionsKey]: vwUserId,
            _vaultwardenInviteSentAt: now,
          } as unknown as Prisma.InputJsonValue,
        },
      });

      return {
        success: true,
        serviceUserId: vwUserId || undefined,
        extraPermissions: { _vaultwardenInviteSentAt: now },
      };
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      logger.error(`Vaultwarden provisioner: provision failed for ${user.email}: ${msg}`);
      return { success: false, error: msg };
    }
  }

  async syncUser(_user: CMUser, _serviceUserId: string): Promise<void> {
    // Vaultwarden has no role sync concept — users manage their own vault
    // Nothing to sync beyond initial invite
  }

  async deactivate(serviceUserId: string): Promise<void> {
    try {
      await vaultwardenClient.deactivateUser(serviceUserId);
      logger.info(`Vaultwarden provisioner: deactivated user ${serviceUserId}`);
    } catch (err) {
      logger.error(`Vaultwarden provisioner: deactivate failed for ${serviceUserId}:`, err);
      throw err;
    }
  }
}

export const vaultwardenProvisioner = new VaultwardenProvisioner();
