<?php

namespace App\Http\Controllers;

use App\Models\Unit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class UnitController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        try {
            $query = Unit::query();

            // Search functionality
            if ($request->has('search')) {
                $search = $request->input('search');
                $query->where(function($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('abbreviation', 'like', "%{$search}%")
                      ->orWhere('description', 'like', "%{$search}%");
                });
            }

            // Filter by status
            if ($request->has('status') && $request->status != '') {
                $query->where('status', $request->status);
            }

            // Filter by base units
            if ($request->has('type') && $request->type == 'base') {
                $query->where('is_base_unit', true);
            } elseif ($request->has('type') && $request->type == 'derived') {
                $query->where('is_base_unit', false);
            }

            // Sorting
            $sortBy = $request->get('sort_by', 'name');
            $sortOrder = $request->get('sort_order', 'asc');
            
            $allowedSort = ['name', 'abbreviation', 'conversion_rate', 'status', 'created_at'];
            if (in_array($sortBy, $allowedSort)) {
                $query->orderBy($sortBy, $sortOrder);
            } else {
                $query->orderBy('name');
            }

            $units = $query->paginate(20)->withQueryString();

            // Statistics
            $stats = [
                'total' => Unit::count(),
                'active' => Unit::where('status', 'active')->count(),
                'base_units' => Unit::where('is_base_unit', true)->count(),
                'derived_units' => Unit::where('is_base_unit', false)->count(),
            ];

            return view('units.index', compact('units', 'stats'));
            
        } catch (\Exception $e) {
            Log::error('Unit index error: ' . $e->getMessage());
            return redirect()->route('dashboard')
                ->with('error', 'Failed to load units. Please try again.');
        }
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $baseUnits = Unit::where('is_base_unit', true)
            ->where('status', 'active')
            ->get();
            
        return view('units.create', compact('baseUnits'));
    }

/**
 * Store a newly created resource in storage.
 */
public function store(Request $request)
{
    try {
        DB::beginTransaction();

        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255|unique:units,name',
            'abbreviation' => 'required|string|max:10|unique:units,abbreviation',
            'description' => 'nullable|string',
            'status' => 'required|in:active,inactive',
            'is_base_unit' => 'boolean',
            'conversion_rate' => [
                'nullable',
                'numeric',
                'min:0.0001',
                function ($attribute, $value, $fail) use ($request) {
                    // Only require conversion rate if not base unit AND base_unit_id is provided
                    if (!$request->is_base_unit && $request->base_unit_id && !$value) {
                        $fail('Conversion rate is required when a base unit is selected.');
                    }
                },
            ],
            'base_unit_id' => [
                'nullable',
                'exists:units,id',
                function ($attribute, $value, $fail) use ($request) {
                    if ($value && $request->is_base_unit) {
                        $fail('Base unit cannot have a parent base unit.');
                    }
                    
                    // Don't require base unit if this is marked as base unit
                    if (!$request->is_base_unit && !$value) {
                        // If there are existing base units, suggest selecting one
                        $baseUnitsCount = Unit::where('is_base_unit', true)->count();
                        if ($baseUnitsCount > 0) {
                            // This is just a suggestion, not a requirement
                            // Remove the fail() call to make it optional
                        }
                    }
                },
            ],
        ], [
            'name.unique' => 'This unit name already exists.',
            'abbreviation.unique' => 'This abbreviation already exists.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        $data = $validator->validated();
        
        // Auto-detect if this should be a base unit
        if (!isset($data['is_base_unit']) || $data['is_base_unit'] === null) {
            $data['is_base_unit'] = !$data['base_unit_id'];
        }
        
        // Set default values
        if ($data['is_base_unit']) {
            $data['conversion_rate'] = 1;
            $data['base_unit_id'] = null;
        } elseif ($data['base_unit_id'] && !$data['conversion_rate']) {
            $data['conversion_rate'] = 1;
        }

        $unit = Unit::create($data);

        // Log activity
        activity()
            ->causedBy(auth()->user())
            ->performedOn($unit)
            ->log('created unit');

        DB::commit();

        return redirect()->route('units.index')
            ->with('success', 'Unit created successfully.');
            
    } catch (\Illuminate\Validation\ValidationException $e) {
        DB::rollBack();
        throw $e;
    } catch (\Exception $e) {
        DB::rollBack();
        Log::error('Unit store error: ' . $e->getMessage());
        return redirect()->back()
            ->with('error', 'Failed to create unit: ' . $e->getMessage())
            ->withInput();
    }
}
    /**
     * Display the specified resource.
     */
    public function show(Unit $unit)
    {
        try {
            $unit->load(['baseUnit', 'derivedUnits', 'products' => function($query) {
                $query->limit(10)->latest();
            }]);

            $relatedUnits = Unit::where('base_unit_id', $unit->base_unit_id)
                ->where('id', '!=', $unit->id)
                ->where('status', 'active')
                ->get();

            return view('units.show', compact('unit', 'relatedUnits'));
            
        } catch (\Exception $e) {
            Log::error('Unit show error: ' . $e->getMessage());
            return redirect()->route('units.index')
                ->with('error', 'Failed to load unit details.');
        }
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Unit $unit)
    {
        $baseUnits = Unit::where('is_base_unit', true)
            ->where('status', 'active')
            ->where('id', '!=', $unit->id)
            ->get();
            
        return view('units.edit', compact('unit', 'baseUnits'));
    }

/**
 * Update the specified resource in storage.
 */
public function update(Request $request, Unit $unit)
{
    try {
        DB::beginTransaction();

        $validator = Validator::make($request->all(), [
            'name' => [
                'required',
                'string',
                'max:255',
                Rule::unique('units')->ignore($unit->id),
            ],
            'abbreviation' => [
                'required',
                'string',
                'max:10',
                Rule::unique('units')->ignore($unit->id),
            ],
            'description' => 'nullable|string',
            'status' => 'required|in:active,inactive',
            'is_base_unit' => 'boolean',
            'conversion_rate' => [
                'nullable',
                'numeric',
                'min:0.0001',
                function ($attribute, $value, $fail) use ($request, $unit) {
                    // Only require conversion rate if not base unit AND base_unit_id is provided
                    if (!$request->is_base_unit && $request->base_unit_id && !$value) {
                        $fail('Conversion rate is required when a base unit is selected.');
                    }
                },
            ],
            'base_unit_id' => [
                'nullable',
                'exists:units,id',
                function ($attribute, $value, $fail) use ($request, $unit) {
                    if ($value == $unit->id) {
                        $fail('A unit cannot be its own base unit.');
                    }
                    
                    if ($value && $request->is_base_unit) {
                        $fail('Base unit cannot have a parent base unit.');
                    }
                },
            ],
        ], [
            'name.unique' => 'This unit name already exists.',
            'abbreviation.unique' => 'This abbreviation already exists.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        $oldData = $unit->toArray();
        $data = $validator->validated();
        
        // Auto-detect if this should be a base unit
        if (!isset($data['is_base_unit']) || $data['is_base_unit'] === null) {
            $data['is_base_unit'] = !$data['base_unit_id'];
        }
        
        // Set default values
        if ($data['is_base_unit']) {
            $data['conversion_rate'] = 1;
            $data['base_unit_id'] = null;
        } elseif ($data['base_unit_id'] && !$data['conversion_rate']) {
            $data['conversion_rate'] = 1;
        }

        $unit->update($data);

        // Log activity
        activity()
            ->causedBy(auth()->user())
            ->performedOn($unit)
            ->withProperties([
                'old' => $oldData,
                'new' => $data
            ])
            ->log('updated unit');

        DB::commit();

        return redirect()->route('units.index')
            ->with('success', 'Unit updated successfully.');
            
    } catch (\Illuminate\Validation\ValidationException $e) {
        DB::rollBack();
        throw $e;
    } catch (\Exception $e) {
        DB::rollBack();
        Log::error('Unit update error: ' . $e->getMessage());
        return redirect()->back()
            ->with('error', 'Failed to update unit: ' . $e->getMessage())
            ->withInput();
    }
}

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Unit $unit)
    {
        try {
            DB::beginTransaction();

            // Check if unit is being used by products
            if ($unit->products()->count() > 0) {
                return redirect()->route('units.index')
                    ->with('error', 'Cannot delete unit because it is being used by products. Please update those products first.');
            }

            // Check if unit is being used as base unit
            if ($unit->derivedUnits()->count() > 0) {
                return redirect()->route('units.index')
                    ->with('error', 'Cannot delete unit because it is being used as base unit for other units. Please update those units first.');
            }

            // Log activity before deletion
            activity()
                ->causedBy(auth()->user())
                ->performedOn($unit)
                ->log('deleted unit');

            $unit->delete();

            DB::commit();

            return redirect()->route('units.index')
                ->with('success', 'Unit deleted successfully.');
                
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Unit destroy error: ' . $e->getMessage());
            return redirect()->route('units.index')
                ->with('error', 'Failed to delete unit. Please try again.');
        }
    }

    /**
     * Search units for AJAX requests.
     */
    public function search(Request $request)
    {
        try {
            $search = $request->input('q');
            $limit = $request->input('limit', 10);
            $type = $request->input('type', 'all');

            $query = Unit::where('status', 'active');

            if ($type === 'base') {
                $query->where('is_base_unit', true);
            } elseif ($type === 'derived') {
                $query->where('is_base_unit', false);
            }

            if (!empty($search)) {
                $query->where(function($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('abbreviation', 'like', "%{$search}%");
                });
            }

            $units = $query->select('id', 'name', 'abbreviation', 'is_base_unit')
                ->orderBy('name')
                ->limit($limit)
                ->get();

            return response()->json($units);
            
        } catch (\Exception $e) {
            Log::error('Unit search error: ' . $e->getMessage());
            return response()->json([], 500);
        }
    }

    /**
     * Bulk delete units.
     */
    public function bulkDelete(Request $request)
    {
        try {
            DB::beginTransaction();

            $validated = $request->validate([
                'unit_ids' => 'required|array',
                'unit_ids.*' => 'exists:units,id',
            ]);

            $units = Unit::whereIn('id', $validated['unit_ids'])->get();
            $deletedCount = 0;
            $failedCount = 0;
            $errors = [];

            foreach ($units as $unit) {
                // Check if unit can be deleted
                if ($unit->products()->count() > 0 || $unit->derivedUnits()->count() > 0) {
                    $failedCount++;
                    $errors[] = "Unit '{$unit->name}' is in use.";
                    continue;
                }

                // Log activity before deletion
                activity()
                    ->causedBy(auth()->user())
                    ->performedOn($unit)
                    ->log('bulk deleted unit');

                $unit->delete();
                $deletedCount++;
            }

            DB::commit();

            $message = "Deleted {$deletedCount} units successfully.";
            if ($failedCount > 0) {
                $message .= " {$failedCount} units could not be deleted.";
            }

            return response()->json([
                'success' => true,
                'message' => $message,
                'deleted_count' => $deletedCount,
                'failed_count' => $failedCount,
                'errors' => $errors,
            ]);
            
        } catch (\Illuminate\Validation\ValidationException $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Validation error',
                'errors' => $e->errors()
            ], 422);
            
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Bulk delete units error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to delete units: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Bulk update units.
     */
    public function bulkUpdate(Request $request)
    {
        try {
            DB::beginTransaction();

            $validated = $request->validate([
                'unit_ids' => 'required|array',
                'unit_ids.*' => 'exists:units,id',
                'data' => 'required|array',
                'data.status' => 'nullable|in:active,inactive',
            ]);

            $units = Unit::whereIn('id', $validated['unit_ids'])->get();
            $updatedCount = 0;

            foreach ($units as $unit) {
                $unit->update(array_filter($validated['data']));
                $updatedCount++;
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => "Updated {$updatedCount} units successfully.",
                'updated_count' => $updatedCount,
            ]);
            
        } catch (\Illuminate\Validation\ValidationException $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Validation error',
                'errors' => $e->errors()
            ], 422);
            
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Bulk update units error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to update units: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Export units.
     */
    public function export(Request $request)
    {
        try {
            $units = Unit::with(['baseUnit'])
                ->orderBy('name')
                ->get();

            $fileName = 'units-' . date('Y-m-d') . '.csv';
            $headers = [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => "attachment; filename=$fileName",
            ];

            $callback = function() use ($units) {
                $file = fopen('php://output', 'w');
                
                // Add BOM for UTF-8
                fwrite($file, "\xEF\xBB\xBF");
                
                // Headers
                fputcsv($file, [
                    'ID', 'Name', 'Abbreviation', 'Base Unit', 'Conversion Rate',
                    'Type', 'Status', 'Description', 'Created At'
                ]);
                
                // Data
                foreach ($units as $unit) {
                    fputcsv($file, [
                        $unit->id,
                        $unit->name,
                        $unit->abbreviation,
                        $unit->baseUnit->name ?? 'Base Unit',
                        $unit->conversion_rate,
                        $unit->is_base_unit ? 'Base Unit' : 'Derived Unit',
                        $unit->status,
                        $unit->description ?? '',
                        $unit->created_at->format('Y-m-d H:i:s'),
                    ]);
                }
                
                fclose($file);
            };

            return response()->stream($callback, 200, $headers);
            
        } catch (\Exception $e) {
            Log::error('Unit export error: ' . $e->getMessage());
            return redirect()->route('units.index')
                ->with('error', 'Failed to export units.');
        }
    }

    /**
     * Get units for AJAX select.
     */
    public function getUnits(Request $request)
    {
        try {
            $search = $request->input('search', '');
            $type = $request->input('type', 'all');
            
            $query = Unit::where('status', 'active');
            
            if ($type === 'base') {
                $query->where('is_base_unit', true);
            } elseif ($type === 'derived') {
                $query->where('is_base_unit', false);
            }
            
            if (!empty($search)) {
                $query->where(function($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('abbreviation', 'like', "%{$search}%");
                });
            }
            
            $units = $query->orderBy('name')
                ->limit(20)
                ->get(['id', 'name', 'abbreviation', 'is_base_unit']);
            
            return response()->json($units);
            
        } catch (\Exception $e) {
            Log::error('Get units error: ' . $e->getMessage());
            return response()->json([], 500);
        }
    }

    /**
     * Convert between units.
     */
    public function convert(Request $request)
    {
        try {
            $validated = $request->validate([
                'from_unit_id' => 'required|exists:units,id',
                'to_unit_id' => 'required|exists:units,id',
                'quantity' => 'required|numeric|min:0',
            ]);

            $fromUnit = Unit::find($validated['from_unit_id']);
            $toUnit = Unit::find($validated['to_unit_id']);
            $quantity = $validated['quantity'];

            $convertedQuantity = $fromUnit->convertTo($toUnit->id, $quantity);

            if ($convertedQuantity === null) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot convert between these units.',
                ]);
            }

            return response()->json([
                'success' => true,
                'data' => [
                    'from_unit' => $fromUnit->full_name,
                    'to_unit' => $toUnit->full_name,
                    'quantity' => $quantity,
                    'converted_quantity' => $convertedQuantity,
                    'converted_quantity_formatted' => number_format($convertedQuantity, 4),
                ],
            ]);
            
        } catch (\Exception $e) {
            Log::error('Unit convert error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to convert units.',
            ], 500);
        }
    }
}