-- 08-backend-pricing-and-security.sql
-- 1. Server-side price calculation RPC (read-only, callable by anon for display)
-- 2. Refactored create_lead RPC that computes prices internally (no price params from frontend)
-- 3. Unique constraint on lead_attachments to enforce max 1 id_document + 1 income_proof per lead

-- =============================================================================
-- 1. calculate_price RPC
-- =============================================================================
create or replace function public.calculate_price(
    p_vehicle_id uuid,
    p_date_from date,
    p_date_to date
)
returns jsonb
language plpgsql
stable
security definer
as $$
declare
    v_vehicle record;
    v_total_days integer;
    v_weekend_days integer;
    v_weekdays integer;
    v_daily_subtotal integer;
    v_weekend_subtotal integer;
    v_subtotal_eur integer;
    v_vat_eur integer;
    v_total_eur integer;
    v_deposit_eur integer;
    v_cur date;
    v_dow integer;
begin
    if p_vehicle_id is null or p_date_from is null or p_date_to is null then
        raise exception 'vehicle_id, date_from and date_to are required';
    end if;

    if p_date_to <= p_date_from then
        raise exception 'date_to must be after date_from';
    end if;

    select daily_price_eur, weekend_price_eur, kaution_eur, max_daily_km, max_km_weekend
      into v_vehicle
      from public.vehicles
     where id = p_vehicle_id;

    if not found then
        raise exception 'Vehicle not found';
    end if;

    -- Count days
    v_total_days := (p_date_to - p_date_from);
    v_weekend_days := 0;
    v_cur := p_date_from;
    while v_cur < p_date_to loop
        v_dow := extract(isodow from v_cur); -- 6=Sat, 7=Sun
        if v_dow in (6, 7) then
            v_weekend_days := v_weekend_days + 1;
        end if;
        v_cur := v_cur + 1;
    end loop;
    v_weekdays := v_total_days - v_weekend_days;

    -- Calculate prices
    v_daily_subtotal := v_weekdays * v_vehicle.daily_price_eur;
    v_weekend_subtotal := v_weekend_days * (case when v_vehicle.weekend_price_eur > 0 then v_vehicle.weekend_price_eur else v_vehicle.daily_price_eur end);
    v_subtotal_eur := v_daily_subtotal + v_weekend_subtotal;
    v_vat_eur := round(v_subtotal_eur * 0.20);
    v_total_eur := v_subtotal_eur + v_vat_eur;
    v_deposit_eur := coalesce(nullif(v_vehicle.kaution_eur, 0), 5000);

    return jsonb_build_object(
        'total_days', v_total_days,
        'weekday_count', v_weekdays,
        'weekend_day_count', v_weekend_days,
        'daily_subtotal', v_daily_subtotal,
        'weekend_subtotal', v_weekend_subtotal,
        'subtotal_eur', v_subtotal_eur,
        'vat_eur', v_vat_eur,
        'total_eur', v_total_eur,
        'deposit_eur', v_deposit_eur,
        'daily_price_eur', v_vehicle.daily_price_eur,
        'weekend_price_eur', (case when v_vehicle.weekend_price_eur > 0 then v_vehicle.weekend_price_eur else v_vehicle.daily_price_eur end),
        'max_daily_km', coalesce(v_vehicle.max_daily_km, 150),
        'max_km_weekend', coalesce(v_vehicle.max_km_weekend, v_vehicle.max_daily_km, 150)
    );
end;
$$;

grant execute on function public.calculate_price(uuid, date, date) to anon, authenticated, service_role;

-- =============================================================================
-- 2. Refactored create_lead – computes prices server-side, no price params
-- =============================================================================

-- Drop old overloaded signatures
drop function if exists public.create_lead(
    text, text, text, uuid, text, date, date, text, text
);
drop function if exists public.create_lead(
    text, text, text, uuid, text, date, date, text, text,
    integer, integer, integer, integer, integer, integer, integer, integer, integer
);
drop function if exists public.create_lead(
    text, text, text, uuid, text, date, date, text, text,
    integer, integer, integer, integer, integer, integer, integer, integer, integer,
    text, text
);

create or replace function public.create_lead(
    p_name text,
    p_email text,
    p_phone text default '',
    p_vehicle_id uuid default null,
    p_vehicle_label text default '',
    p_date_from date default null,
    p_date_to date default null,
    p_message text default '',
    p_source text default 'website',
    p_ip_address text default '',
    p_ip_country text default ''
)
returns uuid
language plpgsql
security definer
as $$
declare
    v_lead_id uuid;
    v_vehicle record;
    v_total_days integer := 0;
    v_weekend_days integer := 0;
    v_weekdays integer := 0;
    v_daily_subtotal integer := 0;
    v_weekend_subtotal integer := 0;
    v_subtotal_eur integer := 0;
    v_vat_eur integer := 0;
    v_total_eur integer := 0;
    v_deposit_eur integer := 0;
    v_cur date;
    v_dow integer;
begin
    -- Compute prices server-side if vehicle and dates are provided
    if p_vehicle_id is not null and p_date_from is not null and p_date_to is not null and p_date_to > p_date_from then
        select daily_price_eur, weekend_price_eur, kaution_eur
          into v_vehicle
          from public.vehicles
         where id = p_vehicle_id;

        if found then
            v_total_days := (p_date_to - p_date_from);
            v_cur := p_date_from;
            while v_cur < p_date_to loop
                v_dow := extract(isodow from v_cur);
                if v_dow in (6, 7) then
                    v_weekend_days := v_weekend_days + 1;
                end if;
                v_cur := v_cur + 1;
            end loop;
            v_weekdays := v_total_days - v_weekend_days;

            v_daily_subtotal := v_weekdays * v_vehicle.daily_price_eur;
            v_weekend_subtotal := v_weekend_days * (case when v_vehicle.weekend_price_eur > 0 then v_vehicle.weekend_price_eur else v_vehicle.daily_price_eur end);
            v_subtotal_eur := v_daily_subtotal + v_weekend_subtotal;
            v_vat_eur := round(v_subtotal_eur * 0.20);
            v_total_eur := v_subtotal_eur + v_vat_eur;
            v_deposit_eur := coalesce(nullif(v_vehicle.kaution_eur, 0), 5000);
        end if;
    end if;

    insert into public.leads (
        name, email, phone, vehicle_id, vehicle_label, date_from, date_to,
        message, source,
        daily_subtotal, weekend_subtotal, subtotal_eur, vat_eur, total_eur, deposit_eur,
        total_days, weekday_count, weekend_day_count, ip_address, ip_country
    ) values (
        p_name, p_email, p_phone, p_vehicle_id, p_vehicle_label, p_date_from, p_date_to,
        p_message, p_source,
        v_daily_subtotal, v_weekend_subtotal, v_subtotal_eur, v_vat_eur, v_total_eur, v_deposit_eur,
        v_total_days, v_weekdays, v_weekend_days, p_ip_address, p_ip_country
    )
    returning id into v_lead_id;
    return v_lead_id;
end;
$$;

grant execute on function public.create_lead(
    text, text, text, uuid, text, date, date, text, text, text, text
) to anon, authenticated, service_role;

-- =============================================================================
-- 3. Enforce max 1 id_document + 1 income_proof per lead
-- =============================================================================

-- Unique partial index: only one 'id_document' per lead
drop index if exists lead_attachments_unique_id_document;
create unique index lead_attachments_unique_id_document
    on public.lead_attachments (lead_id)
    where kind = 'id_document';

-- Unique partial index: only one 'income_proof' per lead
drop index if exists lead_attachments_unique_income_proof;
create unique index lead_attachments_unique_income_proof
    on public.lead_attachments (lead_id)
    where kind = 'income_proof';

notify pgrst, 'reload schema';
