<?php

namespace App\Services;

use App\Models\ManufacturingBOM;
use App\Models\ManufacturingBOMIngredient;
use App\Models\Account;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ManufacturingBOMService
{
    /**
     * Validate BOM ingredients
     */
    public function validateIngredients(ManufacturingBOM $bom): array
    {
        $errors = [];

        // Check if BOM has at least one ingredient
        if ($bom->ingredients()->count() === 0) {
            $errors[] = 'BOM must have at least one ingredient.';
        }

        // Check for duplicate ingredients
        $ingredientIds = $bom->ingredients()->pluck('ingredient_account_id')->toArray();
        $duplicates = array_diff_assoc($ingredientIds, array_unique($ingredientIds));

        if (!empty($duplicates)) {
            $errors[] = 'BOM contains duplicate ingredients.';
        }

        // Validate ingredient accounts are active
        $inactiveIngredients = $bom->ingredients()
            ->whereHas('ingredient', function ($query) {
                $query->where('is_active', false);
            })
            ->with('ingredient')
            ->get();

        foreach ($inactiveIngredients as $ingredient) {
            $errors[] = "Ingredient '{$ingredient->ingredient->name}' is inactive.";
        }

        return $errors;
    }

    /**
     * Check if BOM exists for finished good
     */
    public function checkBOMExistsForFinishedGood(int $finishedGoodsAccountId, ?int $excludeBomId = null): array
    {
        $query = ManufacturingBOM::where('finished_goods_account_id', $finishedGoodsAccountId)
            ->where('is_active', true);

        if ($excludeBomId) {
            $query->where('id', '!=', $excludeBomId);
        }

        $existingBom = $query->first();

        if ($existingBom) {
            $finishedGoods = Account::find($finishedGoodsAccountId);
            return [
                'exists' => true,
                'bom_id' => $existingBom->id,
                'bom_name' => $existingBom->name,
                'finished_goods_name' => $finishedGoods ? $finishedGoods->name : 'Unknown',
                'message' => "A BOM already exists for '{$finishedGoods->name}'. Only one active BOM is allowed per finished good."
            ];
        }

        return [
            'exists' => false,
            'message' => 'No existing BOM found for this finished good.'
        ];
    }

    /**
     * Validate BOM steps
     */
    public function validateSteps(ManufacturingBOM $bom): array
    {
        $errors = [];

        // Check for duplicate sequence orders
        $sequenceOrders = $bom->steps()->pluck('sequence_order')->toArray();
        $duplicates = array_diff_assoc($sequenceOrders, array_unique($sequenceOrders));

        if (!empty($duplicates)) {
            $errors[] = 'BOM contains duplicate sequence orders in steps.';
        }

        // Check for gaps in sequence
        if (!empty($sequenceOrders)) {
            sort($sequenceOrders);
            $expectedSequence = range(1, count($sequenceOrders));

            if ($sequenceOrders !== $expectedSequence) {
                $errors[] = 'BOM steps must have consecutive sequence orders starting from 1.';
            }
        }

        return $errors;
    }

    /**
     * Validate entire BOM
     */
    public function validateBOM(ManufacturingBOM $bom): array
    {
        $errors = [];

        // Validate ingredients
        $ingredientErrors = $this->validateIngredients($bom);
        $errors = array_merge($errors, $ingredientErrors);

        // Validate steps
        $stepErrors = $this->validateSteps($bom);
        $errors = array_merge($errors, $stepErrors);

        // Validate BOM name uniqueness per version
        $existingBom = ManufacturingBOM::where('name', $bom->name)
            ->where('version', $bom->version)
            ->where('id', '!=', $bom->id)
            ->first();

        if ($existingBom) {
            $errors[] = "BOM with name '{$bom->name}' and version {$bom->version} already exists.";
        }

        return $errors;
    }

    /**
     * Get ingredient costs (placeholder for future cost calculation)
     */
    public function getIngredientCosts(ManufacturingBOM $bom): array
    {
        $costs = [];

        foreach ($bom->ingredients as $ingredient) {
            $costs[] = [
                'ingredient_id' => $ingredient->id,
                'ingredient_name' => $ingredient->ingredient->name,
                'quantity_required' => $ingredient->quantity_required,
                'effective_quantity' => $ingredient->effective_quantity,
                'unit' => $ingredient->unit,
                'wastage_type' => $ingredient->wastage_type,
                'wastage_value' => $ingredient->wastage_value,
                'unit_cost' => $ingredient->ingredient->weighted_average_price ?? 0,
                'total_cost' => ($ingredient->ingredient->weighted_average_price ?? 0) * $ingredient->effective_quantity,
            ];
        }

        return $costs;
    }

    /**
     * Clone BOM with new version
     */
    public function cloneBOM(ManufacturingBOM $originalBom, string $newName, int $newVersion): ManufacturingBOM
    {
        return DB::transaction(function () use ($originalBom, $newName, $newVersion) {
            // Create new BOM
            $newBom = ManufacturingBOM::create([
                'name' => $newName,
                'description' => $originalBom->description,
                'version' => $newVersion,
                'is_active' => true,
                'created_by' => auth()->id(),
            ]);

            // Clone steps
            foreach ($originalBom->steps as $step) {
                $newStep = $newBom->steps()->create([
                    'step_name' => $step->step_name,
                    'instruction' => $step->instruction,
                    'sequence_order' => $step->sequence_order,
                ]);

                // Clone step ingredients
                foreach ($step->ingredients as $ingredient) {
                    $newBom->ingredients()->create([
                        'manufacturing_bom_step_id' => $newStep->id,
                        'ingredient_account_id' => $ingredient->ingredient_account_id,
                        'quantity_required' => $ingredient->quantity_required,
                        'unit' => $ingredient->unit,
                        'wastage_type' => $ingredient->wastage_type,
                        'wastage_value' => $ingredient->wastage_value,
                    ]);
                }
            }

            // Clone direct ingredients (not attached to steps)
            foreach ($originalBom->ingredients()->directIngredients()->get() as $ingredient) {
                $newBom->ingredients()->create([
                    'ingredient_account_id' => $ingredient->ingredient_account_id,
                    'quantity_required' => $ingredient->quantity_required,
                    'unit' => $ingredient->unit,
                    'wastage_type' => $ingredient->wastage_type,
                    'wastage_value' => $ingredient->wastage_value,
                ]);
            }

            return $newBom;
        });
    }

    /**
     * Get BOM statistics
     */
    public function getBOMStatistics(ManufacturingBOM $bom): array
    {
        return [
            'total_steps' => $bom->steps()->count(),
            'total_ingredients' => $bom->ingredients()->count(),
            'direct_ingredients' => $bom->ingredients()->directIngredients()->count(),
            'step_ingredients' => $bom->ingredients()->whereNotNull('manufacturing_bom_step_id')->count(),
            'unique_ingredients' => $bom->ingredients()->distinct('ingredient_account_id')->count(),
            'total_effective_quantity' => $bom->ingredients()->get()->sum('effective_quantity'),
        ];
    }

    /**
     * Export BOM data
     */
    public function exportBOM(ManufacturingBOM $bom): array
    {
        $bom->load(['steps.ingredients.ingredient', 'ingredients.ingredient', 'creator']);

        return [
            'bom' => [
                'name' => $bom->name,
                'description' => $bom->description,
                'version' => $bom->version,
                'is_active' => $bom->is_active,
                'created_by' => $bom->creator ? $bom->creator->name : 'N/A',
                'created_at' => $bom->created_at->format('Y-m-d H:i:s'),
            ],
            'steps' => $bom->steps->map(function ($step) {
                return [
                    'step_name' => $step->step_name,
                    'instruction' => $step->instruction,
                    'sequence_order' => $step->sequence_order,
                    'ingredients' => $step->ingredients->map(function ($ingredient) {
                        return [
                            'ingredient_name' => $ingredient->ingredient->name,
                            'ingredient_sku' => $ingredient->ingredient->sku,
                            'quantity_required' => $ingredient->quantity_required,
                            'unit' => $ingredient->unit,
                            'wastage_type' => $ingredient->wastage_type,
                            'wastage_value' => $ingredient->wastage_value,
                            'effective_quantity' => $ingredient->effective_quantity,
                        ];
                    }),
                ];
            }),
            'direct_ingredients' => $bom->ingredients()->directIngredients()->with('ingredient')->get()->map(function ($ingredient) {
                return [
                    'ingredient_name' => $ingredient->ingredient->name,
                    'ingredient_sku' => $ingredient->ingredient->sku,
                    'quantity_required' => $ingredient->quantity_required,
                    'unit' => $ingredient->unit,
                    'wastage_type' => $ingredient->wastage_type,
                    'wastage_value' => $ingredient->wastage_value,
                    'effective_quantity' => $ingredient->effective_quantity,
                ];
            }),
        ];
    }
}
