<?php

namespace App\Services;

use App\Models\ScoopWeightConfig;
use App\Models\OrderItem;
use Illuminate\Support\Collection;

class ScoopWeightService
{
    /**
     * Calculate weight distribution for multiple flavours in an order
     *
     * @param array $flavours [['product_id' => 1, 'scoop_count' => 2], ['product_id' => 2, 'scoop_count' => 1]]
     * @return array ['total_scoops' => 3, 'weight_per_scoop' => 56.67, 'flavours' => [...]]
     */
    public function calculateWeightDistribution(array $flavours): array
    {
        // Calculate total scoops
        $totalScoops = array_sum(array_column($flavours, 'scoop_count'));

        if ($totalScoops === 0) {
            return [
                'total_scoops' => 0,
                'total_weight_grams' => 0,
                'weight_per_scoop_grams' => 0,
                'flavours' => [],
            ];
        }

        // Get weight per scoop based on total scoop count
        $weightPerScoop = ScoopWeightConfig::calculateWeightPerScoop($totalScoops);
        $totalWeight = ScoopWeightConfig::calculateTotalWeight($totalScoops);

        // Calculate weight for each flavour
        $flavourWeights = [];
        foreach ($flavours as $flavour) {
            $scoopCount = $flavour['scoop_count'];
            $weightGrams = round($weightPerScoop * $scoopCount, 2);

            $flavourWeights[] = [
                'product_id' => $flavour['product_id'],
                'product_name' => $flavour['product_name'] ?? null,
                'scoop_count' => $scoopCount,
                'weight_grams' => $weightGrams,
                'weight_per_scoop_grams' => $weightPerScoop,
            ];
        }

        return [
            'total_scoops' => $totalScoops,
            'total_weight_grams' => $totalWeight,
            'weight_per_scoop_grams' => $weightPerScoop,
            'flavours' => $flavourWeights,
            'calculation_method' => $this->getCalculationMethod($totalScoops),
        ];
    }

    /**
     * Calculate weight for a single order item with multiple flavours
     *
     * @param OrderItem $orderItem
     * @return array
     */
    public function calculateOrderItemWeights(OrderItem $orderItem): array
    {
        // Parse inner options (flavours/scoops)
        $innerOptions = is_array($orderItem->inner_options)
            ? $orderItem->inner_options
            : json_decode($orderItem->inner_options, true);

        if (empty($innerOptions)) {
            // No flavours specified, use quantity as scoop count
            $totalScoops = $orderItem->quantity;
            $weightPerScoop = ScoopWeightConfig::calculateWeightPerScoop($totalScoops);

            return [
                'total_scoops' => $totalScoops,
                'total_weight_grams' => round($weightPerScoop * $totalScoops, 2),
                'weight_per_scoop_grams' => $weightPerScoop,
                'flavours' => [
                    [
                        'product_id' => $orderItem->product_id,
                        'product_name' => $orderItem->product_name,
                        'scoop_count' => $totalScoops,
                        'weight_grams' => round($weightPerScoop * $totalScoops, 2),
                    ],
                ],
            ];
        }

        // Build flavours array from inner options
        $flavours = [];
        foreach ($innerOptions as $option) {
            // Assume each inner option represents a flavour selection
            // with optional scoop count in the option data
            $scoopCount = $option['scoop_count'] ?? 1;

            $flavours[] = [
                'product_id' => $option['inner_option_id'] ?? $option['id'],
                'product_name' => $option['name'] ?? 'Unknown',
                'scoop_count' => $scoopCount,
            ];
        }

        return $this->calculateWeightDistribution($flavours);
    }

    /**
     * Get configuration for a specific scoop count
     */
    public function getConfigForScoops(int $scoopCount): ?ScoopWeightConfig
    {
        return ScoopWeightConfig::getWeightForScoops($scoopCount);
    }

    /**
     * Get all active scoop weight configurations
     */
    public function getAllConfigurations(): Collection
    {
        return ScoopWeightConfig::getAllActive();
    }

    /**
     * Update or create scoop weight configuration
     */
    public function updateConfiguration(int $scoopCount, array $data): ScoopWeightConfig
    {
        $config = ScoopWeightConfig::where('scoop_count', $scoopCount)->first();

        if ($config) {
            $config->update($data);
        } else {
            $data['scoop_count'] = $scoopCount;
            $config = ScoopWeightConfig::create($data);
        }

        // Auto-calculate weight per scoop if not provided
        if (!isset($data['weight_per_scoop_grams']) && isset($data['total_weight_grams'])) {
            $config->weight_per_scoop_grams = round($data['total_weight_grams'] / $scoopCount, 2);
            $config->save();
        }

        return $config;
    }

    /**
     * Determine which calculation method was used
     */
    private function getCalculationMethod(int $totalScoops): string
    {
        $config = ScoopWeightConfig::getWeightForScoops($totalScoops);

        if ($config) {
            return 'exact_config';
        }

        $lower = ScoopWeightConfig::where('scoop_count', '<', $totalScoops)
            ->where('is_active', true)
            ->exists();

        $upper = ScoopWeightConfig::where('scoop_count', '>', $totalScoops)
            ->where('is_active', true)
            ->exists();

        if ($lower && $upper) {
            return 'interpolated';
        }

        return 'extrapolated';
    }

    /**
     * Validate weight against tolerance
     */
    public function validateWeight(int $scoopCount, float $actualWeight): array
    {
        $config = ScoopWeightConfig::getWeightForScoops($scoopCount);

        if (!$config) {
            return [
                'valid' => true,
                'message' => 'No configuration found for ' . $scoopCount . ' scoops',
                'within_tolerance' => null,
            ];
        }

        $withinTolerance = $config->isWeightWithinTolerance($actualWeight);

        return [
            'valid' => $withinTolerance,
            'expected_weight' => (float) $config->total_weight_grams,
            'actual_weight' => $actualWeight,
            'difference' => $actualWeight - $config->total_weight_grams,
            'difference_percentage' => (($actualWeight - $config->total_weight_grams) / $config->total_weight_grams) * 100,
            'min_allowed' => (float) $config->min_weight_grams,
            'max_allowed' => (float) $config->max_weight_grams,
            'within_tolerance' => $withinTolerance,
            'message' => $withinTolerance
                ? 'Weight within acceptable range'
                : 'Weight outside tolerance range',
        ];
    }

    /**
     * Calculate recommended pricing based on weight
     */
    public function calculatePricingByWeight(float $weightGrams, float $pricePerGram): float
    {
        return round($weightGrams * $pricePerGram, 2);
    }

    /**
     * Get weight efficiency (grams per scoop) across all configs
     */
    public function getWeightEfficiencyReport(): array
    {
        $configs = ScoopWeightConfig::getAllActive();

        $report = [];
        foreach ($configs as $config) {
            $efficiency = $config->weight_per_scoop_grams;
            $reduction = 0;

            if ($config->scoop_count > 1) {
                $singleScoopConfig = ScoopWeightConfig::getWeightForScoops(1);
                if ($singleScoopConfig) {
                    $reduction = (($singleScoopConfig->weight_per_scoop_grams - $efficiency) / $singleScoopConfig->weight_per_scoop_grams) * 100;
                }
            }

            $report[] = [
                'scoop_count' => $config->scoop_count,
                'total_weight_grams' => (float) $config->total_weight_grams,
                'weight_per_scoop_grams' => (float) $config->weight_per_scoop_grams,
                'efficiency_reduction_percent' => round($reduction, 2),
                'tolerance_range' => [
                    'min' => (float) $config->min_weight_grams,
                    'max' => (float) $config->max_weight_grams,
                ],
            ];
        }

        return $report;
    }
}
