-- ============================================================
-- Cruce de Cuentas GLM - Bono 14 Guatemala
-- Script incremental / idempotente
-- ============================================================
-- Objetivo:
--   Habilitar y verificar que Bono 14 use la MISMA infraestructura
--   de reporte único ya instalada, pero con una identidad independiente:
--
--       GT-<AÑO>-07-bono14
--
-- Ejemplo:
--       GT-2026-07-bono14
--
-- No crea otra tabla de históricos y no elimina datos existentes.
-- Puede ejecutarse nuevamente sin borrar reportes.
-- ============================================================

begin;

-- ------------------------------------------------------------
-- 1. Validación de prerrequisitos de la versión "reporte único"
-- ------------------------------------------------------------
do $$
declare
  v_missing text[] := array[]::text[];
begin
  if to_regclass('public.cruces_cuentas_gt_reportes') is null then
    raise exception
      'No existe public.cruces_cuentas_gt_reportes. Instala primero la estructura base de Cruce de Cuentas.';
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'report_identity'
  ) then
    v_missing := array_append(v_missing, 'report_identity');
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'updated_at'
  ) then
    v_missing := array_append(v_missing, 'updated_at');
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'country'
  ) then
    v_missing := array_append(v_missing, 'country');
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'year'
  ) then
    v_missing := array_append(v_missing, 'year');
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'month'
  ) then
    v_missing := array_append(v_missing, 'month');
  end if;

  if not exists (
    select 1
    from information_schema.columns
    where table_schema = 'public'
      and table_name = 'cruces_cuentas_gt_reportes'
      and column_name = 'period_type'
  ) then
    v_missing := array_append(v_missing, 'period_type');
  end if;

  if cardinality(v_missing) > 0 then
    raise exception
      'Faltan columnas requeridas en public.cruces_cuentas_gt_reportes: %. Ejecuta primero el script de REPORTE ÚNICO POR PERÍODO.',
      array_to_string(v_missing, ', ');
  end if;
end;
$$;

-- ------------------------------------------------------------
-- 2. Constructor canónico de identidad
-- ------------------------------------------------------------
-- Se mantiene genérico para nómina GT, nómina TT y Bono 14.
create or replace function public.cruce_cuentas_build_report_identity(
  p_country text,
  p_year integer,
  p_month integer,
  p_period_type text
)
returns text
language sql
immutable
as $$
  select
    upper(trim(coalesce(p_country, 'GT')))
    || '-' ||
    coalesce(p_year, 0)::text
    || '-' ||
    lpad(coalesce(p_month, 0)::text, 2, '0')
    || '-' ||
    lower(trim(coalesce(p_period_type, 'periodo')));
$$;

-- ------------------------------------------------------------
-- 3. Trigger de identidad / updated_at
-- ------------------------------------------------------------
-- Reinstalado de forma idempotente para garantizar que un UPSERT de
-- Bono 14 mantenga la misma identidad y actualice updated_at.
create or replace function public.cruce_cuentas_set_report_identity()
returns trigger
language plpgsql
set search_path = public
as $$
declare
  v_canonical text;
begin
  v_canonical :=
    public.cruce_cuentas_build_report_identity(
      coalesce(new.country, 'GT'),
      new.year,
      new.month,
      new.period_type
    );

  if tg_op = 'INSERT' then
    if nullif(trim(coalesce(new.report_identity, '')), '') is null then
      new.report_identity := v_canonical;
    end if;
  else
    -- Los duplicados históricos antiguos conservan su sufijo :legacy:.
    if coalesce(old.report_identity, '') like '%:legacy:%' then
      new.report_identity := old.report_identity;
    else
      new.report_identity := v_canonical;
    end if;
  end if;

  new.updated_at := now();
  return new;
end;
$$;

drop trigger if exists trg_cruce_cuentas_report_identity
  on public.cruces_cuentas_gt_reportes;

create trigger trg_cruce_cuentas_report_identity
before insert or update on public.cruces_cuentas_gt_reportes
for each row
execute function public.cruce_cuentas_set_report_identity();

-- ------------------------------------------------------------
-- 4. Garantizar unicidad por identidad
-- ------------------------------------------------------------
-- La versión de reporte único ya debe tener este índice. Se valida antes
-- de recrearlo para no alterar ni eliminar históricos existentes.
do $$
begin
  if not exists (
    select 1
    from pg_indexes
    where schemaname = 'public'
      and tablename = 'cruces_cuentas_gt_reportes'
      and indexname = 'ux_cruces_cuentas_reportes_report_identity'
  ) then
    if exists (
      select report_identity
      from public.cruces_cuentas_gt_reportes
      where report_identity is not null
      group by report_identity
      having count(*) > 1
    ) then
      raise exception
        'Existen report_identity duplicados. Ejecuta primero el script de REPORTE ÚNICO POR PERÍODO para aplicar su backfill seguro antes de Bono 14.';
    end if;

    create unique index ux_cruces_cuentas_reportes_report_identity
      on public.cruces_cuentas_gt_reportes (report_identity);
  end if;
end;
$$;

-- Índice auxiliar específico para consultas/soporte de Bono 14.
create index if not exists ix_cruces_cuentas_gt_reportes_bono14_updated
  on public.cruces_cuentas_gt_reportes (year, updated_at desc)
  where upper(coalesce(country, 'GT')) = 'GT'
    and lower(coalesce(period_type, '')) = 'bono14';

-- ------------------------------------------------------------
-- 5. RPC que n8n consulta ANTES de crear/reutilizar el Google Sheet
-- ------------------------------------------------------------
create or replace function public.cruce_cuentas_get_reporte_periodo(
  p_country text,
  p_year integer,
  p_month integer,
  p_period_type text
)
returns jsonb
language plpgsql
stable
security definer
set search_path = public
as $$
declare
  v_identity text;
  v_report public.cruces_cuentas_gt_reportes%rowtype;
begin
  v_identity :=
    public.cruce_cuentas_build_report_identity(
      p_country,
      p_year,
      p_month,
      p_period_type
    );

  select r.*
    into v_report
  from public.cruces_cuentas_gt_reportes r
  where r.report_identity = v_identity
  order by
    r.updated_at desc nulls last,
    r.created_at desc nulls last
  limit 1;

  if not found then
    return jsonb_build_object(
      'ok', true,
      'found', false,
      'report_identity', v_identity,
      'report', null
    );
  end if;

  return jsonb_build_object(
    'ok', true,
    'found', true,
    'report_identity', v_identity,
    'report', jsonb_build_object(
      'id', v_report.id,
      'report_identity', v_report.report_identity,
      'country', v_report.country,
      'year', v_report.year,
      'month', v_report.month,
      'period_type', v_report.period_type,
      'period_label', v_report.period_label,
      'spreadsheet_id', v_report.spreadsheet_id,
      'report_url', v_report.report_url,
      'estado', v_report.estado,
      'created_at', v_report.created_at,
      'updated_at', v_report.updated_at
    )
  );
end;
$$;

revoke all on function public.cruce_cuentas_get_reporte_periodo(text, integer, integer, text)
  from public, anon, authenticated;

grant execute on function public.cruce_cuentas_get_reporte_periodo(text, integer, integer, text)
  to service_role;

commit;

-- ============================================================
-- VALIDACIÓN FINAL (solo lectura)
-- Debe devolver: GT-2026-07-bono14
-- ============================================================
select
  public.cruce_cuentas_build_report_identity(
    'GT',
    2026,
    7,
    'bono14'
  ) as identidad_bono14_esperada;

-- Si ya existe un Bono 14 2026, esta consulta devuelve found=true.
-- Si todavía no se ha generado, devuelve found=false (lo esperado antes
-- de la primera ejecución).
select public.cruce_cuentas_get_reporte_periodo(
  'GT',
  2026,
  7,
  'bono14'
) as estado_bono14_2026;
