import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ExternalServicesCredentials } from './credentials.entity';
import * as crypto from 'crypto';

@Injectable()
export class CredentialsService {
    private readonly logger = new Logger(CredentialsService.name);
    // We need the PUBLIC key to encrypt.
    // Assuming we can get it from env RSA_PUBLIC_KEY,
    // OR derive it from RSA_PRIVATE_KEY_BASE64 if provided.
    // The Go backend uses RSA_PRIVATE_KEY_BASE64.
    // We will try to load the same private key and extract public key from it.

    constructor(
        @InjectRepository(ExternalServicesCredentials)
        private credentialsRepo: Repository<ExternalServicesCredentials>,
    ) { }

    async list() {
        const creds = await this.credentialsRepo.find();
        return creds.map((c) => ({
            service_name: c.serviceName,
            updated_at: c.updatedAt,
            updated_by: c.updatedBy,
            is_configured: true,
        }));
    }

    async save(serviceName: string, payload: any, updatedBy: string) {
        const jsonString = JSON.stringify(payload);
        const encrypted = this.encryptPayload(jsonString);

        let cred = await this.credentialsRepo.findOne({ where: { serviceName } });
        if (!cred) {
            cred = this.credentialsRepo.create({ serviceName });
        } else {
            throw new BadRequestException('Credentials already configured for this service.');
        }
        cred.encryptedPayload = encrypted;
        cred.updatedBy = updatedBy;

        await this.credentialsRepo.save(cred);
        this.logger.log(`Updated credentials for service: ${serviceName}`);
    }

    async delete(serviceName: string) {
        await this.credentialsRepo.delete({ serviceName });
        this.logger.log(`Deleted credentials for service: ${serviceName}`);
    }

    private encryptPayload(payload: string): string {
        const privateKeyBase64 = process.env.RSA_PRIVATE_KEY_BASE64 || process.env.JWT_SECRET; // Fallback to avoid crash but will fail encryption if not RSA

        if (!process.env.RSA_PRIVATE_KEY_BASE64) {
            // Dev fallback logic or throw
            throw new Error('RSA_PRIVATE_KEY_BASE64 not configured');
        }

        try {
            const privateKeyPem = Buffer.from(process.env.RSA_PRIVATE_KEY_BASE64, 'base64').toString('utf-8');

            // Extract Public Key from Private Key
            const publicKey = crypto.createPublicKey(privateKeyPem);

            // Encrypt using RSA-OAEP-SHA256 to match Go's implementation
            const buffer = Buffer.from(payload, 'utf-8');
            const encrypted = crypto.publicEncrypt(
                {
                    key: publicKey,
                    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
                    oaepHash: 'sha256',
                },
                buffer
            );

            return encrypted.toString('base64');
        } catch (e) {
            this.logger.error('Encryption failed', e);
            throw new Error('Failed to encrypt payload');
        }
    }
}
