import * as fs from "fs";
import * as mysql from "mysql2/promise";
import * as path from "path";
import { DataSource } from "typeorm";
import { CredentialsCryptoService } from "../src/control-plane/credentials-crypto.service";
import { Tenant } from "../src/control-plane/entities/tenant.entity";

// Repara UN tenant cuya tabla `migrations` ya tiene registrada
// AddTiendaFacturacionPosConfig1780400000000 como aplicada (asi que
// TenantReconciliationService.reconcile() no la vuelve a intentar), pero cuyo
// `maetie` real nunca recibio el ALTER TABLE -- confirmado en un tenant real
// (Demo Ventas, incidente del 2026-09-09): reconciliar devolvia "0
// migraciones aplicadas" y el login/switch-tenant seguian tirando
// ER_BAD_FIELD_ERROR sobre taller_facturacion_pos_habilitada. La causa mas
// probable es que ese tenant se armo copiando la tabla `migrations` de otro
// (mismo conteo de filas que el codigo fuente) sin correr el DDL real.
//
// IDEMPOTENTE: consulta INFORMATION_SCHEMA.COLUMNS antes de agregar cada
// columna -- correrlo dos veces, o contra un tenant que SI tiene todo, es un
// no-op. No toca la tabla `migrations` a proposito: el objetivo es que el
// esquema real quede correcto, no que el bookkeeping quede "honesto" sobre
// como se llego ahi.
const FACTURACION_POS_COLUMNS: Array<{ name: string; ddl: string }> = [
  { name: "taller_facturacion_pos_habilitada", ddl: "tinyint(1) NOT NULL DEFAULT 0" },
  { name: "taller_facturacion_pos_url", ddl: "varchar(500) NULL" },
  { name: "taller_facturacion_pos_username", ddl: "varchar(128) NULL" },
  { name: "taller_facturacion_pos_password_encrypted", ddl: "text NULL" },
  { name: "taller_facturacion_pos_computadora", ddl: "varchar(64) NULL" },
  { name: "taller_facturacion_pos_precio_decimales", ddl: "int NULL" },
];

// Mismo motivo que en migrate-identidades.ts: dentro de backend-tools no hay
// .env, las variables ya llegan inyectadas por docker-compose.yml.
function loadRootEnv(): void {
  const envPath = path.join(__dirname, "..", "..", ".env");
  if (!fs.existsSync(envPath)) return;
  for (const line of fs.readFileSync(envPath, "utf8").split(/\r?\n/)) {
    const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
    if (m && !process.env[m[1]]) process.env[m[1]] = m[2];
  }
}

function buildCryptoService(): CredentialsCryptoService {
  const fakeConfigService = { get: (key: string) => process.env[key] };
  const crypto = new CredentialsCryptoService(fakeConfigService as any);
  crypto.onModuleInit();
  return crypto;
}

function buildControlPlaneDataSource(): DataSource {
  return new DataSource({
    type: "mysql",
    host: process.env.CONTROL_PLANE_DB_HOST,
    port: parseInt(process.env.CONTROL_PLANE_DB_PORT || "3306", 10),
    username: process.env.CONTROL_PLANE_DB_USERNAME,
    password: process.env.CONTROL_PLANE_DB_PASSWORD,
    database: process.env.CONTROL_PLANE_DB_DATABASE,
    entities: [Tenant],
    synchronize: false,
  });
}

async function repair(tenantId: number): Promise<void> {
  loadRootEnv();
  const crypto = buildCryptoService();
  const ds = buildControlPlaneDataSource();
  await ds.initialize();

  try {
    const tenant = await ds.getRepository(Tenant).findOne({ where: { id: tenantId } });
    if (!tenant) {
      throw new Error(`Tenant ${tenantId} no encontrado en mbinvtaller.tenants`);
    }

    const password = crypto.decrypt(tenant.dbPasswordEncrypted);
    const conn = await mysql.createConnection({
      host: tenant.dbHost,
      port: tenant.dbPort,
      user: tenant.dbUser,
      password,
      database: tenant.dbName,
    });

    try {
      const [rows] = await conn.query<mysql.RowDataPacket[]>(
        "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'maetie'",
        [tenant.dbName],
      );
      const existentes = new Set((rows as any[]).map((r) => r.COLUMN_NAME));
      const faltantes = FACTURACION_POS_COLUMNS.filter((c) => !existentes.has(c.name));

      if (faltantes.length === 0) {
        console.log(
          `[repair-maetie-facturacion-pos] tenant ${tenantId} (${tenant.codigo}): ya tenia las 6 columnas, nada que hacer.`,
        );
        return;
      }

      const alterSql =
        "ALTER TABLE maetie " + faltantes.map((c) => `ADD COLUMN ${c.name} ${c.ddl}`).join(", ");
      console.log(
        `[repair-maetie-facturacion-pos] tenant ${tenantId} (${tenant.codigo}): agregando ${faltantes
          .map((c) => c.name)
          .join(", ")}`,
      );
      await conn.query(alterSql);
      console.log(`[repair-maetie-facturacion-pos] tenant ${tenantId} (${tenant.codigo}): listo.`);
    } finally {
      await conn.end();
    }
  } finally {
    await ds.destroy();
  }
}

async function main(): Promise<void> {
  const tenantId = Number(process.argv[2]);
  if (!process.argv[2] || Number.isNaN(tenantId)) {
    console.error("Uso: npx ts-node scripts/repair-tenant-maetie-facturacion-pos.ts <tenantId>");
    process.exit(1);
  }
  await repair(tenantId);
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
