create or replace function medreport.upsert_health_benefits(
    p_benefit_distribution_schedule_id uuid
)
returns void
language plpgsql
security definer
as $$
declare
    member_record record;
    expires_date timestamp with time zone;
    v_company_id uuid;
    v_benefit_amount numeric;
    existing_entry_id uuid;
begin
    -- Expires on first day of next year.
    expires_date := date_trunc('year', now() + interval '1 year');

    -- Get company_id and benefit_amount from benefit_distribution_schedule
    select company_id, benefit_amount into v_company_id, v_benefit_amount
    from medreport.benefit_distribution_schedule
    where id = p_benefit_distribution_schedule_id;

    -- Get all personal accounts that are members of this company
    for member_record in
        select distinct a.id as personal_account_id
        from medreport.accounts a
        join medreport.accounts_memberships am on a.id = am.user_id
        where am.account_id = v_company_id
        and a.is_personal_account = true
    loop

        -- Check if there is already a balance entry for this personal account from the same company in same month
        select id into existing_entry_id
        from medreport.account_balance_entries
        where entry_type = 'benefit'
        and account_id = member_record.personal_account_id
        and source_company_id = v_company_id
        and date_trunc('month', created_at) = date_trunc('month', now())
        LIMIT 1;

        if existing_entry_id is not null then
            update medreport.account_balance_entries set
                amount = v_benefit_amount,
                expires_at = expires_date,
                benefit_distribution_schedule_id = p_benefit_distribution_schedule_id
            where id = existing_entry_id;
        else
            -- Insert new balance entry for personal account
            insert into medreport.account_balance_entries (
                account_id,
                amount,
                entry_type,
                description,
                source_company_id,
                created_by,
                expires_at,
                benefit_distribution_schedule_id
            ) values (
                member_record.personal_account_id,
                v_benefit_amount,
                'benefit',
                'Health benefit from company',
                v_company_id,
                auth.uid(),
                expires_date,
                p_benefit_distribution_schedule_id
            );
        end if;
    end loop;
end;
$$;

grant execute on function medreport.upsert_health_benefits(uuid) to authenticated, service_role;

create or replace function medreport.process_periodic_benefit_distributions()
returns void
language plpgsql
as $$
declare
    schedule_record record;
    next_distribution_date timestamp with time zone;
begin
    -- Get all active schedules that are due for distribution
    for schedule_record in
        select *
        from medreport.benefit_distribution_schedule
        where is_active = true
        and next_distribution_at <= now()
    loop
        -- Distribute benefits
        perform medreport.upsert_health_benefits(
            schedule_record.id
        );
        
        -- Calculate next distribution date
        next_distribution_date := medreport.calculate_next_distribution_date(
            schedule_record.benefit_occurrence,
            now()
        );
        
        -- Update the schedule
        update medreport.benefit_distribution_schedule
        set 
            last_distributed_at = now(),
            next_distribution_at = next_distribution_date,
            updated_at = now()
        where id = schedule_record.id;
    end loop;
end;
$$;

create or replace function medreport.trigger_distribute_benefits()
returns trigger
language plpgsql
security definer
as $$
declare
    v_benefit_distribution_schedule_id uuid;
begin
    -- Only distribute if benefit_amount is set and greater than 0
    if new.benefit_amount is not null and new.benefit_amount > 0 then
        -- Create or update the distribution schedule for future distributions
        v_benefit_distribution_schedule_id := medreport.upsert_benefit_distribution_schedule(
            new.account_id,
            new.benefit_amount,
            coalesce(new.benefit_occurance, 'yearly')
        );

        -- Distribute benefits to all company members immediately
        if new.benefit_amount > old.benefit_amount then
            perform medreport.upsert_health_benefits(
                v_benefit_distribution_schedule_id
            );
        end if;
    else
        -- If benefit_amount is 0 or null, deactivate the schedule
        update medreport.benefit_distribution_schedule
        set is_active = false, updated_at = now()
        where company_id = new.account_id;
    end if;
    
    return new;
end;
$$;

drop function if exists medreport.distribute_health_benefits(uuid);

create or replace function medreport.trigger_benefits_on_new_membership()
returns trigger
language plpgsql
security definer
as $$
declare
    v_schedule_id uuid;
begin
    select bds.id into v_schedule_id
    from medreport.benefit_distribution_schedule bds
    where bds.company_id = new.account_id
    limit 1;

    if v_schedule_id is not NULL then
        PERFORM medreport.upsert_health_benefits(v_schedule_id);
    end if;

    return new;
end;
$$;

create trigger trigger_insert_benefits_on_accounts_membership
after insert on medreport.accounts_memberships
for EACH row
execute function medreport.trigger_benefits_on_new_membership();
