import { prisma } from '../../config/database';
import type { SiteSettings } from '@prisma/client';
import type { UpdateSiteSettingsInput } from './settings.schemas';
import { encrypt, decrypt } from '../../utils/crypto';
import { env } from '../../config/env';

// Fields to strip from public responses
const SENSITIVE_FIELDS = ['smtpHost', 'smtpPort', 'smtpUser', 'smtpPass', 'smtpFromAddress', 'testEmailRecipient', 'giteaApiToken', 'giteaOauthClientSecret', 'smsTermuxApiUrl', 'smsTermuxApiKey', 'smsTailscaleApiKey'] as const;

// Fields that are encrypted at rest in the database
const ENCRYPTED_FIELDS = ['smtpPass', 'giteaApiToken', 'giteaOauthClientSecret', 'smsTermuxApiKey', 'smsTailscaleApiKey'] as const;

/** Decrypt encrypted fields on a settings object (mutates in place) */
function decryptSettings(settings: SiteSettings): SiteSettings {
  for (const field of ENCRYPTED_FIELDS) {
    const value = settings[field];
    if (typeof value === 'string' && value) {
      (settings as Record<string, unknown>)[field] = decrypt(value);
    }
  }
  return settings;
}

export const siteSettingsService = {
  /** Full settings with encrypted fields decrypted (admin use) */
  async get() {
    let settings = await prisma.siteSettings.findFirst();
    if (!settings) {
      settings = await prisma.siteSettings.create({ data: {} });
    }
    return decryptSettings(settings);
  },

  /** Full settings + _effective object resolving actual runtime SMTP config (admin use) */
  async getEffective() {
    const settings = await this.get();
    const provider = settings.smtpActiveProvider || 'mailhog';

    let host: string, port: number, user: string, hasPassword: boolean, fromAddress: string, fromName: string;

    if (provider === 'mailhog') {
      host = env.SMTP_HOST;
      port = 1025;
      user = '';
      hasPassword = false;
      fromAddress = settings.smtpFromAddress || env.SMTP_FROM;
      fromName = settings.emailFromName || env.SMTP_FROM_NAME;
    } else {
      host = settings.smtpHost || env.SMTP_HOST;
      port = settings.smtpPort || env.SMTP_PORT;
      user = settings.smtpUser || env.SMTP_USER;
      hasPassword = !!(settings.smtpPass || env.SMTP_PASS);
      fromAddress = settings.smtpFromAddress || env.SMTP_FROM;
      fromName = settings.emailFromName || env.SMTP_FROM_NAME;
    }

    const testMode = settings.emailTestMode;
    const testRecipient = settings.testEmailRecipient || env.TEST_EMAIL_RECIPIENT;

    return {
      ...settings,
      _effective: {
        provider,
        host,
        port,
        user,
        hasPassword,
        fromAddress,
        fromName,
        testMode,
        testRecipient,
      },
    };
  },

  /** Public-safe settings (strips SMTP credentials) */
  async getPublic(): Promise<Omit<SiteSettings, typeof SENSITIVE_FIELDS[number]>> {
    const settings = await this.get();
    const result = { ...settings } as Record<string, unknown>;
    for (const field of SENSITIVE_FIELDS) {
      delete result[field];
    }
    return result as Omit<SiteSettings, typeof SENSITIVE_FIELDS[number]>;
  },

  async update(data: UpdateSiteSettingsInput) {
    // Encrypt sensitive fields before writing to DB
    const toWrite = { ...data };
    for (const field of ENCRYPTED_FIELDS) {
      if (field in toWrite && typeof toWrite[field] === 'string' && toWrite[field]) {
        (toWrite as Record<string, unknown>)[field] = encrypt(toWrite[field] as string);
      }
    }

    const existing = await prisma.siteSettings.findFirst();
    let settings: SiteSettings;
    if (existing) {
      settings = await prisma.siteSettings.update({
        where: { id: existing.id },
        data: toWrite,
      });
    } else {
      settings = await prisma.siteSettings.create({ data: toWrite });
    }
    return decryptSettings(settings);
  },
};
