<?php

namespace SplitPay\Core;

use SplitPay\Contracts\OrderAdapterInterface;
use SplitPay\Contracts\TransferableItem;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class TransferCalculator {

	private OrderAdapterInterface $orderAdapter;
	private array $settings;

	public function __construct( OrderAdapterInterface $orderAdapter, array $globalSettings ) {
		$this->orderAdapter = $orderAdapter;
		$this->settings     = array_merge(
			[
				'transfer_taxes'          => '0',
				'tax_transfer_type'       => 'partial',
				'coupon_adjust_transfers' => '0',
			],
			$globalSettings
		);
	}

	/**
	 * @param array $globalAccounts Rows from the connected-accounts table (bsd_connected_id_table).
	 * @return array Transfer plan with keys: total_global_transfer_amount, product_transfers,
	 *               global_shipping_amount, product_shipping_transfers, global_tax_total, all_taxes_array.
	 */
	public function calculate( array $globalAccounts ): array {
		$items   = $this->orderAdapter->getItems();
		$coupons = $this->parseCoupons();

		$fixedCartDiscount     = $coupons['fixed_cart'];
		$percentDiscount       = $coupons['percent'];
		$productCouponMap      = $coupons['product_discounts'];
		$shippingTotal         = $this->orderAdapter->getShippingTotal();
		$globalShippingAmount  = $shippingTotal;
		$allTaxesArray         = $this->orderAdapter->getTaxItems();
		$taxTransferType       = $this->settings['tax_transfer_type'];

		$globalDiscountedTotal = 0.0;
		$globalTax             = 0.0;
		$productTransfers      = [];
		$productShippingXfers  = [];

		foreach ( $items as $item ) {
			$globalShippingAmount -= $item->shipping_cost;

			if ( empty( $item->connected_accounts ) ) {
				$discountedLine = $this->applyItemCoupons( $item, $productCouponMap, $percentDiscount );
				$globalDiscountedTotal += $discountedLine;
				$globalShippingAmount  += $item->shipping_cost;

				$itemTax = $this->sumTaxData( $item->tax_data );
				$globalTax += $itemTax;
				continue;
			}

			$discountedLine = $this->applyItemCoupons( $item, $productCouponMap, $percentDiscount );
			$itemTaxTotal   = $this->sumTaxData( $item->tax_data );
			$accountResults = $this->calculateProductAccountTransfers( $item, $discountedLine, $itemTaxTotal, $taxTransferType );

			if ( $taxTransferType === 'all' && ! empty( $accountResults ) ) {
				$accountResults = $this->redistributeTaxAll( $accountResults, $itemTaxTotal );
			}

			foreach ( $accountResults as $ar ) {
				$productTransfers[] = $ar;
			}

			$shippingResults = $this->calculateProductShippingTransfers( $item );
			foreach ( $shippingResults as $sr ) {
				$productShippingXfers[] = $sr;
			}
		}

		if ( $fixedCartDiscount > 0 ) {
			$globalDiscountedTotal -= $fixedCartDiscount;
		}

		$subtotal = $this->orderAdapter->getSubtotal();
		if ( $globalDiscountedTotal > $subtotal ) {
			$globalDiscountedTotal = $subtotal;
		}

		if ( $globalDiscountedTotal < 0 ) {
			$globalDiscountedTotal = 0.0;
		}

		return [
			'total_global_transfer_amount' => (float) $globalDiscountedTotal,
			'product_transfers'            => $productTransfers,
			'global_shipping_amount'       => (float) $globalShippingAmount,
			'product_shipping_transfers'   => $productShippingXfers,
			'global_tax_total'             => (float) $globalTax,
			'all_taxes_array'              => $allTaxesArray,
		];
	}

	private function parseCoupons(): array {
		$fixedCart       = 0.0;
		$percentAmount  = 0.0;
		$productMap     = [];
		$coupons        = $this->orderAdapter->getCoupons();

		if ( $this->settings['coupon_adjust_transfers'] !== '1' ) {
			return [
				'fixed_cart'        => $fixedCart,
				'percent'           => $percentAmount,
				'product_discounts' => $productMap,
			];
		}

		foreach ( $coupons as $coupon ) {
			$type       = $coupon['discount_type'] ?? '';
			$discount   = (float) ( $coupon['discount'] ?? 0 );
			$amount     = (float) ( $coupon['discount_amount'] ?? 0 );
			$productIds = $coupon['product_ids'] ?? [];

			if ( empty( $productIds ) && $type === 'fixed_cart' ) {
				$fixedCart += $discount;
			} elseif ( empty( $productIds ) && $type === 'percent' ) {
				$percentAmount = $amount;
			} elseif ( ! empty( $productIds ) ) {
				foreach ( $productIds as $pid ) {
					$productMap[ $pid ] = $discount;
				}
			}
		}

		return [
			'fixed_cart'        => $fixedCart,
			'percent'           => $percentAmount,
			'product_discounts' => $productMap,
		];
	}

	private function applyItemCoupons( TransferableItem $item, array $productCouponMap, float $percentDiscount ): float {
		$lineTotal = $item->line_total - $item->product_discount;

		if ( isset( $productCouponMap[ $item->product_id ] ) ) {
			$lineTotal -= $productCouponMap[ $item->product_id ];
		}

		if ( $percentDiscount > 0 ) {
			$lineTotal -= $item->line_total * ( $percentDiscount / 100 );
		}

		return max( 0.0, $lineTotal );
	}

	private function sumTaxData( array $taxData ): float {
		$total = 0.0;
		foreach ( $taxData as $val ) {
			$total += (float) $val;
		}
		return $total;
	}

	/**
	 * Per-account transfer amounts for a single product-level item.
	 */
	private function calculateProductAccountTransfers(
		TransferableItem $item,
		float $discountedLine,
		float $itemTaxTotal,
		string $taxTransferType
	): array {
		$results = [];

		foreach ( $item->connected_accounts as $idx => $accountId ) {
			$transferType = $item->transfer_types[ $idx ] ?? 'percentage';
			$accountTax   = 0.0;
			$transferAmt  = 0.0;
			$pctOrAmt     = 0.0;

			if ( $transferType === 'percentage' ) {
				$pct         = (float) ( $item->transfer_percentages[ $idx ] ?? 0 );
				$pctOrAmt    = $pct;
				$pctFactor   = $pct / 100;
				$transferAmt = $discountedLine * $pctFactor;

				if ( $taxTransferType === 'partial' ) {
					$accountTax = $itemTaxTotal * $pctFactor;
				}
			} else {
				$fixedAmt = (float) ( $item->transfer_amounts[ $idx ] ?? 0 );
				$totalFixed = $fixedAmt * $item->quantity;
				$pctOrAmt   = $totalFixed;

				if ( $discountedLine <= 0 ) {
					continue;
				}

				$transferAmt = min( $totalFixed, $discountedLine );

				if ( $taxTransferType === 'partial' && $item->unit_price > 0 ) {
					$accountTax = ( $fixedAmt / $item->unit_price ) * $itemTaxTotal;
				}
			}

			$results[] = [
				'product_id'                    => $item->product_id,
				'connected_acc_id'              => $accountId,
				'transfer_amount'               => (float) $transferAmt,
				'transfer_type'                 => $transferType,
				'transfer_percentage_or_amount' => $pctOrAmt,
				'account_wise_tax'              => (float) $accountTax,
				'product_type'                  => $item->product_type,
				'product_price'                 => $discountedLine,
			];
		}

		return $results;
	}

	/**
	 * When tax_transfer_type = 'all', redistribute tax proportionally
	 * based on each account's share of the total product transfer.
	 */
	private function redistributeTaxAll( array $accountResults, float $itemTaxTotal ): array {
		$totalTransferForProduct = 0.0;
		foreach ( $accountResults as $ar ) {
			$totalTransferForProduct += $ar['transfer_amount'];
		}

		if ( $totalTransferForProduct <= 0 ) {
			return $accountResults;
		}

		foreach ( $accountResults as &$ar ) {
			$ratio                = $ar['transfer_amount'] / $totalTransferForProduct;
			$ar['account_wise_tax'] = $itemTaxTotal * $ratio;
		}
		unset( $ar );

		return $accountResults;
	}

	private function calculateProductShippingTransfers( TransferableItem $item ): array {
		$results          = [];
		$remainingShip    = $item->shipping_cost;
		$originalShipping = $item->shipping_cost;

		if ( $remainingShip <= 0 ) {
			return $results;
		}

		foreach ( $item->connected_accounts as $idx => $accountId ) {
			$settings = $item->shipping_transfer_settings[ $idx ] ?? [];
			$shipType = $settings['type'] ?? ( $item->transfer_types[ $idx ] ?? 'percentage' );
			$shipPct  = (float) ( $settings['percentage'] ?? 0 );
			$shipAmt  = (float) ( $settings['amount'] ?? 0 );

			$transferShipCost = 0.0;
			$pctOrAmt         = 0.0;

			if ( $shipType === 'percentage' && $shipPct > 0 ) {
				$pctOrAmt         = $shipPct;
				$transferShipCost = $originalShipping * ( $shipPct / 100 );
				$transferShipCost = min( $transferShipCost, $remainingShip );
			} elseif ( $shipType === 'amount' && $shipAmt > 0 ) {
				$pctOrAmt         = $shipAmt;
				$transferShipCost = min( $shipAmt, $remainingShip );
			}

			if ( $transferShipCost <= 0 ) {
				continue;
			}

			$transferShipCost = (float) number_format( $transferShipCost, 2, '.', '' );
			$remainingShip   -= $transferShipCost;

			$results[] = [
				'product_id'                    => $item->product_id,
				'connected_acc_id'              => $accountId,
				'transfer_amount'               => $transferShipCost,
				'transfer_type'                 => $shipType,
				'transfer_percentage_or_amount' => $pctOrAmt,
			];
		}

		return $results;
	}
}
