import { sql } from '../../db.js';
import {
  INTEGRATION_PROVIDERS,
  type IntegrationProvider,
  type IntegrationPublic,
} from './types.js';

type Row = {
  provider: IntegrationProvider;
  enabled: boolean;
  config: Record<string, unknown> | null;
  secret_api_key: string | null;
  secret_token: string | null;
  secret_password: string | null;
  updated_at: string;
};

function asConfig(raw: Record<string, unknown> | null): Record<string, string> {
  const out: Record<string, string> = {};
  if (!raw) return out;
  for (const [k, v] of Object.entries(raw)) {
    if (v == null) continue;
    out[k] = String(v);
  }
  return out;
}

function toPublic(row: Row): IntegrationPublic {
  return {
    provider: row.provider,
    enabled: row.enabled,
    config: asConfig(row.config),
    has_api_key: Boolean(row.secret_api_key?.trim()),
    has_token: Boolean(row.secret_token?.trim()),
    has_password: Boolean(row.secret_password?.trim()),
    updated_at: row.updated_at,
  };
}

export type IntegrationSecrets = {
  apiKey: string | null;
  token: string | null;
  password: string | null;
};

export const integrationSettingsService = {
  async list(): Promise<IntegrationPublic[]> {
    const rows = await sql<Row[]>`
      SELECT provider, enabled, config, secret_api_key, secret_token, secret_password, updated_at
      FROM ticket_integrations
      ORDER BY provider
    `;
    const byProvider = new Map(rows.map(r => [r.provider, r]));
    return INTEGRATION_PROVIDERS.map(p => {
      const row = byProvider.get(p);
      if (row) return toPublic(row);
      return {
        provider: p,
        enabled: false,
        config: {},
        has_api_key: false,
        has_token: false,
        has_password: false,
        updated_at: new Date(0).toISOString(),
      };
    });
  },

  async getEnabled(): Promise<IntegrationPublic[]> {
    const all = await this.list();
    return all.filter(i => i.enabled);
  },

  async getRow(provider: IntegrationProvider): Promise<Row | null> {
    const [row] = await sql<Row[]>`
      SELECT provider, enabled, config, secret_api_key, secret_token, secret_password, updated_at
      FROM ticket_integrations WHERE provider = ${provider}
    `;
    return row ?? null;
  },

  async getSecrets(provider: IntegrationProvider): Promise<{
    enabled: boolean;
    config: Record<string, string>;
    secrets: IntegrationSecrets;
  } | null> {
    const row = await this.getRow(provider);
    if (!row) return null;
    return {
      enabled: row.enabled,
      config: asConfig(row.config),
      secrets: {
        apiKey: row.secret_api_key?.trim() || null,
        token: row.secret_token?.trim() || null,
        password: row.secret_password?.trim() || null,
      },
    };
  },

  async upsert(
    provider: IntegrationProvider,
    patch: {
      enabled?: boolean;
      config?: Record<string, string>;
      api_key?: string | null;
      token?: string | null;
      password?: string | null;
    },
  ): Promise<IntegrationPublic> {
    const cur = await this.getRow(provider);
    const enabled = patch.enabled ?? cur?.enabled ?? false;
    const config = { ...asConfig(cur?.config ?? null), ...(patch.config ?? {}) };
    // Omit or blank secret fields mean "keep existing"
    const apiKey =
      patch.api_key === undefined || patch.api_key === ''
        ? cur?.secret_api_key ?? null
        : patch.api_key;
    const token =
      patch.token === undefined || patch.token === ''
        ? cur?.secret_token ?? null
        : patch.token;
    const password =
      patch.password === undefined || patch.password === ''
        ? cur?.secret_password ?? null
        : patch.password;

    const [row] = await sql<Row[]>`
      INSERT INTO ticket_integrations (provider, enabled, config, secret_api_key, secret_token, secret_password, updated_at)
      VALUES (
        ${provider}, ${enabled}, ${sql.json(config as never)},
        ${apiKey}, ${token}, ${password}, NOW()
      )
      ON CONFLICT (provider) DO UPDATE SET
        enabled = EXCLUDED.enabled,
        config = EXCLUDED.config,
        secret_api_key = EXCLUDED.secret_api_key,
        secret_token = EXCLUDED.secret_token,
        secret_password = EXCLUDED.secret_password,
        updated_at = NOW()
      RETURNING provider, enabled, config, secret_api_key, secret_token, secret_password, updated_at
    `;
    return toPublic(row);
  },
};
