import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { EncryptionService } from '../../common/services/encryption.service';
import { ConnectIntegrationDto } from './dto/connect-integration.dto';

@Injectable()
export class BusinessService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly encryptionService: EncryptionService,
  ) {}

  async listIntegrations(businessId: string) {
    const integrations = await this.prisma.businessIntegration.findMany({
      where: { businessId },
    });

    // Mask sensitive credentials when sending to frontend
    return integrations.map((integration) => {
      let credentials: Record<string, unknown> = {};
      try {
        credentials = this.encryptionService.decryptJson<
          Record<string, unknown>
        >(integration.credentialsEncrypted);
      } catch {
        // Fallback if formatting was custom
        credentials = {};
      }

      const maskedCredentials: Record<string, unknown> = {};
      for (const [key, value] of Object.entries(credentials)) {
        if (
          typeof value === 'string' &&
          (key.toLowerCase().includes('key') ||
            key.toLowerCase().includes('secret') ||
            key.toLowerCase().includes('token'))
        ) {
          maskedCredentials[key] =
            value.length > 8
              ? `${value.substring(0, 4)}...${value.substring(value.length - 4)}`
              : '********';
        } else {
          maskedCredentials[key] = value;
        }
      }

      return {
        id: integration.id,
        integrationType: integration.integrationType,
        integrationName: integration.integrationName,
        status: integration.status,
        lastConnectedAt: integration.lastConnectedAt,
        createdAt: integration.createdAt,
        credentials: maskedCredentials,
      };
    });
  }

  async connectIntegration(businessId: string, dto: ConnectIntegrationDto) {
    // Check if integration already exists for this business of the same type
    const existing = await this.prisma.businessIntegration.findFirst({
      where: { businessId, integrationType: dto.integrationType },
    });

    const finalCredentials: Record<string, unknown> = { ...dto.credentials };
    if (existing) {
      try {
        const savedCreds = this.encryptionService.decryptJson<
          Record<string, unknown>
        >(existing.credentialsEncrypted);
        for (const [key, value] of Object.entries(finalCredentials)) {
          if (
            typeof value === 'string' &&
            (value.includes('...') || value.includes('***'))
          ) {
            finalCredentials[key] = savedCreds[key];
          }
        }
      } catch {
        // ignore decryption error
      }
    }

    // Trim string credentials
    for (const [key, value] of Object.entries(finalCredentials)) {
      if (typeof value === 'string') {
        finalCredentials[key] = value.trim();
      }
    }

    const credentialsEncrypted =
      this.encryptionService.encryptJson(finalCredentials);

    let integration;
    if (existing) {
      integration = await this.prisma.businessIntegration.update({
        where: { id: existing.id },
        data: {
          integrationName: dto.integrationName,
          credentialsEncrypted,
          status: 'ACTIVE',
          lastConnectedAt: new Date(),
        },
      });
    } else {
      integration = await this.prisma.businessIntegration.create({
        data: {
          businessId,
          integrationType: dto.integrationType,
          integrationName: dto.integrationName,
          credentialsEncrypted,
          status: 'ACTIVE',
          lastConnectedAt: new Date(),
        },
      });
    }

    return {
      id: integration.id,
      integrationType: integration.integrationType,
      integrationName: integration.integrationName,
      status: integration.status,
    };
  }

  async getDecryptedCredentials(businessId: string, integrationType: string) {
    const integration = await this.prisma.businessIntegration.findFirst({
      where: { businessId, integrationType, status: 'ACTIVE' },
    });

    if (!integration) {
      return null;
    }

    try {
      return this.encryptionService.decryptJson<Record<string, unknown>>(
        integration.credentialsEncrypted,
      );
    } catch {
      return null;
    }
  }

  async updateLastConnected(integrationId: string) {
    await this.prisma.businessIntegration.update({
      where: { id: integrationId },
      data: { lastConnectedAt: new Date() },
    });
  }
}
