-- =========================================================
-- TABLERO CDC - Catálogo dinámico de tarifario + guardado seguro de links + RPC de totales
-- Seguro para producción: no borra proyectos, no altera Google Sheets, no cambia n8n.
-- La fuente de mantenimiento del tarifario será Google Sheets; n8n sincroniza hacia esta tabla.
-- =========================================================

-- 1) Catálogo dinámico de tarifas estándar.
-- La app mantiene el tarifario base como respaldo. Esta tabla es el destino normalizado
-- que n8n llenará leyendo el Google Sheet del tarifario. La app solo consume esta tabla.
create table if not exists public.tablero_cdc_tariff_catalog (
  id text primary key,
  catalog_item_id text not null,
  section text not null check (section in ('grafico', 'estrategia')),
  category text not null default '',
  service text not null default '',
  notes text not null default '',
  work_type_id text not null default 'reference',
  work_type_label text not null default 'Referencia',
  work_type_short_label text not null default 'Ref.',
  hour_reference text not null default '',
  level_id text not null default 'project',
  level_label text not null default 'Precio único',
  reference text not null default '',
  reference_min numeric,
  reference_max numeric,
  level_hint text not null default '',
  sort_order integer not null default 9999,
  is_active boolean not null default true,
  created_by uuid references auth.users(id),
  updated_by uuid references auth.users(id),
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

create index if not exists tablero_cdc_tariff_catalog_section_idx
  on public.tablero_cdc_tariff_catalog(section, is_active, sort_order);

create index if not exists tablero_cdc_tariff_catalog_item_idx
  on public.tablero_cdc_tariff_catalog(catalog_item_id);

alter table public.tablero_cdc_tariff_catalog enable row level security;

drop policy if exists "tablero_cdc_tariff_catalog_select_authenticated" on public.tablero_cdc_tariff_catalog;
drop policy if exists "tablero_cdc_tariff_catalog_insert_pricing_admins" on public.tablero_cdc_tariff_catalog;
drop policy if exists "tablero_cdc_tariff_catalog_update_pricing_admins" on public.tablero_cdc_tariff_catalog;
drop policy if exists "tablero_cdc_tariff_catalog_delete_pricing_admins" on public.tablero_cdc_tariff_catalog;

create policy "tablero_cdc_tariff_catalog_select_authenticated"
  on public.tablero_cdc_tariff_catalog
  for select
  to authenticated
  using (true);

create policy "tablero_cdc_tariff_catalog_insert_pricing_admins"
  on public.tablero_cdc_tariff_catalog
  for insert
  to authenticated
  with check (
    lower(coalesce(auth.jwt() ->> 'email', '')) in (
      'gmarrero@gomezleemarketing.com',
      'iaracena@gomezleemarketing.com'
    )
  );

create policy "tablero_cdc_tariff_catalog_update_pricing_admins"
  on public.tablero_cdc_tariff_catalog
  for update
  to authenticated
  using (
    lower(coalesce(auth.jwt() ->> 'email', '')) in (
      'gmarrero@gomezleemarketing.com',
      'iaracena@gomezleemarketing.com'
    )
  )
  with check (
    lower(coalesce(auth.jwt() ->> 'email', '')) in (
      'gmarrero@gomezleemarketing.com',
      'iaracena@gomezleemarketing.com'
    )
  );

-- No recomendamos borrar tarifas usadas históricamente. La app usa activar/desactivar.
-- Aun así dejamos delete restringido por si en pruebas se necesita limpiar un registro creado por error.
create policy "tablero_cdc_tariff_catalog_delete_pricing_admins"
  on public.tablero_cdc_tariff_catalog
  for delete
  to authenticated
  using (
    lower(coalesce(auth.jwt() ->> 'email', '')) in (
      'gmarrero@gomezleemarketing.com',
      'iaracena@gomezleemarketing.com'
    )
  );

create or replace function public.set_tablero_cdc_tariff_catalog_updated_at()
returns trigger
language plpgsql
as $$
begin
  new.updated_at = now();
  new.updated_by = auth.uid();
  if tg_op = 'INSERT' then
    new.created_by = coalesce(new.created_by, auth.uid());
  end if;
  return new;
end;
$$;

drop trigger if exists trg_tablero_cdc_tariff_catalog_updated_at on public.tablero_cdc_tariff_catalog;

create trigger trg_tablero_cdc_tariff_catalog_updated_at
before insert or update on public.tablero_cdc_tariff_catalog
for each row
execute function public.set_tablero_cdc_tariff_catalog_updated_at();

-- 2) Guardado seguro de links de Propuesta / Artes Finales.
-- La app llama esta función para mover links de un campo a otro en una sola operación transaccional.
-- Si cualquier insert falla, el delete también se revierte automáticamente.
create or replace function public.tablero_cdc_replace_project_links(
  p_project_id uuid,
  p_links jsonb default '[]'::jsonb
)
returns void
language plpgsql
security invoker
set search_path = public
as $$
begin
  delete from public.tablero_cdc_project_links
  where project_id = p_project_id;

  insert into public.tablero_cdc_project_links (project_id, link_type, url, label)
  select
    p_project_id,
    nullif(trim(link_type), ''),
    trim(url),
    nullif(trim(label), '')
  from jsonb_to_recordset(coalesce(p_links, '[]'::jsonb)) as x(
    link_type text,
    url text,
    label text
  )
  where nullif(trim(url), '') is not null;
end;
$$;

grant execute on function public.tablero_cdc_replace_project_links(uuid, jsonb) to authenticated;


-- 3) RPC paginado actualizado para que el monto interno solo viaje a Marrero e Isaac.
-- No cambia datos. Solo reemplaza la función de lectura si ya existe.
create or replace function public.tablero_cdc_get_projects_paginated(
  p_tab text default 'todos',
  p_search text default '',
  p_page integer default 1,
  p_page_size integer default 24,
  p_country text default '',
  p_brand text default '',
  p_client text default '',
  p_cm text default ''
)
returns jsonb
language sql
stable
security invoker
set search_path = public
as $$
  with params as (
    select
      lower(coalesce(nullif(trim(p_tab), ''), 'todos')) as tab,
      trim(coalesce(p_search, '')) as search_text,
      greatest(coalesce(p_page, 1), 1) as page_number,
      least(greatest(coalesce(p_page_size, 24), 1), 100) as page_size,
      trim(coalesce(p_country, '')) as country_filter,
      trim(coalesce(p_brand, '')) as brand_filter,
      trim(coalesce(p_client, '')) as client_filter,
      trim(coalesce(p_cm, '')) as cm_filter
  ),
  base_filtered as (
    select p.*
    from public.tablero_cdc_projects p
    cross join params prm
    where
      case
        when prm.tab in ('abiertos', 'activos', 'active', 'open') then
          coalesce(nullif(trim(p.status), ''), 'Activo') = 'Activo'
        when prm.tab in ('cerrados', 'closed') then
          coalesce(nullif(trim(p.status), ''), 'Activo') <> 'Activo'
        else
          true
      end
      and (
        prm.search_text = ''
        or coalesce(p.title, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.client, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.brand, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.country, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.requested_by, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.country_manager, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.description, '') ilike '%' || prm.search_text || '%'
      )
  ),
  filtered as (
    select bf.*
    from base_filtered bf
    cross join params prm
    where
      (prm.country_filter = '' or coalesce(bf.country, '') ilike '%' || prm.country_filter || '%')
      and (prm.brand_filter = '' or coalesce(bf.brand, '') ilike '%' || prm.brand_filter || '%')
      and (prm.client_filter = '' or coalesce(bf.client, '') ilike '%' || prm.client_filter || '%')
      and (prm.cm_filter = '' or coalesce(bf.country_manager, '') ilike '%' || prm.cm_filter || '%')
  ),
  total as (
    select count(*)::integer as total_count
    from filtered
  ),
  paged as (
    select f.*
    from filtered f
    cross join params prm
    order by f.created_at desc nulls last, f.id desc
    limit (select page_size from params)
    offset ((select page_number - 1 from params) * (select page_size from params))
  ),
  option_values as (
    select
      coalesce(
        (
          select jsonb_agg(value order by value)
          from (
            select distinct trim(country) as value
            from base_filtered
            where nullif(trim(coalesce(country, '')), '') is not null
          ) countries
        ),
        '[]'::jsonb
      ) as countries,
      coalesce(
        (
          select jsonb_agg(value order by value)
          from (
            select distinct trim(brand) as value
            from base_filtered
            where nullif(trim(coalesce(brand, '')), '') is not null
          ) brands
        ),
        '[]'::jsonb
      ) as brands,
      coalesce(
        (
          select jsonb_agg(value order by value)
          from (
            select distinct trim(client) as value
            from base_filtered
            where nullif(trim(coalesce(client, '')), '') is not null
          ) clients
        ),
        '[]'::jsonb
      ) as clients,
      coalesce(
        (
          select jsonb_agg(value order by value)
          from (
            select distinct trim(country_manager) as value
            from base_filtered
            where nullif(trim(coalesce(country_manager, '')), '') is not null
          ) cms
        ),
        '[]'::jsonb
      ) as cms
  )
  select jsonb_build_object(
    'total_count', (select total_count from total),
    'filter_options', jsonb_build_object(
      'countries', (select countries from option_values),
      'brands', (select brands from option_values),
      'clients', (select clients from option_values),
      'cms', (select cms from option_values)
    ),
    'projects', coalesce(
      (
        select jsonb_agg(
          jsonb_build_object(
            'id', p.id,
            'title', p.title,
            'client', p.client,
            'brand', p.brand,
            'country', p.country,
            'requested_by', p.requested_by,
            'country_manager', p.country_manager,
            'description', p.description,
            'status', p.status,
            'internal_amount', case
              when lower(coalesce(auth.jwt() ->> 'email', '')) in (
                'gmarrero@gomezleemarketing.com',
                'iaracena@gomezleemarketing.com'
              )
                then to_jsonb(p.internal_amount)
              else 'null'::jsonb
            end,
            'brief_link', p.brief_link,
            'created_at', p.created_at,
            'extra_data', p.extra_data,
            'project_links', coalesce(
              (
                select jsonb_agg(
                  jsonb_build_object(
                    'id', l.id,
                    'link_type', l.link_type,
                    'url', l.url,
                    'label', l.label
                  )
                  order by l.label asc nulls last, l.id asc
                )
                from public.tablero_cdc_project_links l
                where l.project_id = p.id
              ),
              '[]'::jsonb
            )
          )
          order by p.created_at desc nulls last, p.id desc
        )
        from paged p
      ),
      '[]'::jsonb
    )
  );
$$;

grant execute on function public.tablero_cdc_get_projects_paginated(text, text, integer, integer, text, text, text, text) to authenticated;

-- 4) RPC de total tarifado global/filtrado.
-- Calcula en Supabase el total de Interno Cargado y la cantidad de proyectos según los mismos filtros de la pantalla.
-- Solo Marrero e Isaac reciben valores reales; otros usuarios reciben 0.
create or replace function public.tablero_cdc_get_pricing_summary(
  p_tab text default 'todos',
  p_search text default '',
  p_country text default '',
  p_brand text default '',
  p_client text default '',
  p_cm text default ''
)
returns jsonb
language sql
stable
security invoker
set search_path = public
as $$
  with allowed as (
    select lower(coalesce(auth.jwt() ->> 'email', '')) in (
      'gmarrero@gomezleemarketing.com',
      'iaracena@gomezleemarketing.com'
    ) as can_view_pricing
  ),
  params as (
    select
      lower(coalesce(nullif(trim(p_tab), ''), 'todos')) as tab,
      trim(coalesce(p_search, '')) as search_text,
      trim(coalesce(p_country, '')) as country_filter,
      trim(coalesce(p_brand, '')) as brand_filter,
      trim(coalesce(p_client, '')) as client_filter,
      trim(coalesce(p_cm, '')) as cm_filter
  ),
  base_filtered as (
    select p.*
    from public.tablero_cdc_projects p
    cross join params prm
    where
      case
        when prm.tab in ('abiertos', 'activos', 'active', 'open') then
          coalesce(nullif(trim(p.status), ''), 'Activo') = 'Activo'
        when prm.tab in ('cerrados', 'closed') then
          coalesce(nullif(trim(p.status), ''), 'Activo') <> 'Activo'
        else
          true
      end
      and (
        prm.search_text = ''
        or coalesce(p.title, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.client, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.brand, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.country, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.requested_by, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.country_manager, '') ilike '%' || prm.search_text || '%'
        or coalesce(p.description, '') ilike '%' || prm.search_text || '%'
      )
  ),
  filtered as (
    select bf.*
    from base_filtered bf
    cross join params prm
    where
      (prm.country_filter = '' or coalesce(bf.country, '') ilike '%' || prm.country_filter || '%')
      and (prm.brand_filter = '' or coalesce(bf.brand, '') ilike '%' || prm.brand_filter || '%')
      and (prm.client_filter = '' or coalesce(bf.client, '') ilike '%' || prm.client_filter || '%')
      and (prm.cm_filter = '' or coalesce(bf.country_manager, '') ilike '%' || prm.cm_filter || '%')
  ),
  totals as (
    select
      count(*)::integer as project_count,
      coalesce(
        sum(
          greatest(
            coalesce(nullif(trim(internal_amount::text), '')::numeric, 0),
            0
          )
        ),
        0
      )::numeric as total_amount
    from filtered
  )
  select case
    when (select can_view_pricing from allowed) then
      jsonb_build_object(
        'total_amount', (select total_amount from totals),
        'project_count', (select project_count from totals)
      )
    else
      jsonb_build_object(
        'total_amount', 0,
        'project_count', 0
      )
  end;
$$;

grant execute on function public.tablero_cdc_get_pricing_summary(text, text, text, text, text, text) to authenticated;

select
  'tablero_cdc_tariff_catalog, safe links y RPC de totales listos' as status,
  (select count(*) from public.tablero_cdc_tariff_catalog) as tarifas_dinamicas_actuales;
