<?php

namespace App\Support;

use App\Models\Expense;
use App\Models\Group;
use App\Models\Person;

class WeshareMath
{
    /**
     * Mimics src/lib/sample-data.ts getGroupBalances().
     *
     * @return array<int, array{userId:string,user:Person,amount:float}>
     */
    public static function groupBalances(Group $group, iterable $expenses): array
    {
        $balanceMap = [];
        foreach ($group->members as $m) {
            $balanceMap[$m->id] = 0.0;
        }

        foreach ($expenses as $exp) {
            if (!($exp instanceof Expense)) {
                continue;
            }
            if ($exp->group_id !== $group->id || $exp->shared_list_id) {
                continue;
            }

            $payerId = (string) $exp->paid_by_person_id;
            $balanceMap[$payerId] = ($balanceMap[$payerId] ?? 0.0) + (float) $exp->amount;

            $split = is_array($exp->split_among) ? $exp->split_among : [];
            foreach ($split as $row) {
                // We accept either { user: { id }, amount } OR { userId, amount }.
                $uid = (string) (data_get($row, 'user.id') ?? data_get($row, 'userId') ?? '');
                if ($uid === '') {
                    continue;
                }
                $amt = (float) (data_get($row, 'amount') ?? 0);
                $balanceMap[$uid] = ($balanceMap[$uid] ?? 0.0) - $amt;
            }
        }

        $out = [];
        foreach ($group->members as $m) {
            $out[] = [
                'userId' => $m->id,
                'user' => $m,
                'amount' => (float) ($balanceMap[$m->id] ?? 0.0),
            ];
        }
        return $out;
    }

    /**
     * @return array<int, array{from:Person,to:Person,amount:float}>
     */
    public static function simplifiedSettlementsForGroup(Group $group, iterable $expenses): array
    {
        $balances = self::groupBalances($group, $expenses);

        $creditors = [];
        $debtors = [];
        foreach ($balances as $row) {
            $amt = round((float) $row['amount'], 2);
            if ($amt > 0.009) {
                $creditors[] = ['user' => $row['user'], 'amount' => $amt];
            } elseif ($amt < -0.009) {
                $debtors[] = ['user' => $row['user'], 'amount' => abs($amt)];
            }
        }

        usort($creditors, fn ($a, $b) => $b['amount'] <=> $a['amount']);
        usort($debtors, fn ($a, $b) => $b['amount'] <=> $a['amount']);

        $out = [];
        $i = 0;
        $j = 0;
        while ($i < count($debtors) && $j < count($creditors)) {
            $pay = min($debtors[$i]['amount'], $creditors[$j]['amount']);
            $pay = round($pay, 2);
            if ($pay > 0.009) {
                $out[] = [
                    'from' => $debtors[$i]['user'],
                    'to' => $creditors[$j]['user'],
                    'amount' => $pay,
                ];
            }
            $debtors[$i]['amount'] = round($debtors[$i]['amount'] - $pay, 2);
            $creditors[$j]['amount'] = round($creditors[$j]['amount'] - $pay, 2);
            if ($debtors[$i]['amount'] <= 0.009) {
                $i++;
            }
            if ($creditors[$j]['amount'] <= 0.009) {
                $j++;
            }
        }

        return $out;
    }
}

