<?php

namespace App\Service\Admin;

use App\Http\Resources\ServiceItemResource;
use App\Models\ServiceItem;
use App\Models\ServiceCategory;
use App\Models\FeatureType;
use App\Models\FeatureOption;
use App\Models\ServiceItemFeature;
use App\Models\ServiceItemFeatureOption;
use App\Traits\JsonResponseTrait;
use App\Traits\PaginationResponseTrait;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Log;

class ServiceItemService
{
    use JsonResponseTrait, PaginationResponseTrait;

    /**
     * Get all service items with search, sort, filter and pagination
     */
    public function getAllServiceItems(array $filters = [])
    {
        $query = ServiceItem::with([
            'serviceCategory',
            'serviceItemFeatures.featureType',
            'serviceItemFeatureOptions.featureOption'
        ]);

        // Search functionality
        if (!empty($filters['search'])) {
            $searchTerm = $filters['search'];
            $query->where(function ($q) use ($searchTerm) {
                $q->where('name', 'LIKE', "%{$searchTerm}%")
                    ->orWhere('description', 'LIKE', "%{$searchTerm}%")
                    ->orWhere('slug', 'LIKE', "%{$searchTerm}%")
                    ->orWhereHas('serviceCategory', function ($categoryQuery) use ($searchTerm) {
                        $categoryQuery->where('name', 'LIKE', "%{$searchTerm}%");
                    });
            });
        }

        // Filter by category
        if (!empty($filters['service_category_id'])) {
            $query->where('service_category_id', $filters['service_category_id']);
        }

        // Filter by active status
        if (isset($filters['is_active'])) {
            $query->where('is_active', (bool) $filters['is_active']);
        }

        // Filter by price range
        if (!empty($filters['min_base_price'])) {
            $query->where('base_price', '>=', $filters['min_base_price']);
        }

        if (!empty($filters['max_base_price'])) {
            $query->where('base_price', '<=', $filters['max_base_price']);
        }

        // Filter by unit
        if (!empty($filters['unit'])) {
            $query->where('unit', $filters['unit']);
        }

        // Date range filtering
        if (!empty($filters['created_from'])) {
            $query->whereDate('created_at', '>=', $filters['created_from']);
        }

        if (!empty($filters['created_to'])) {
            $query->whereDate('created_at', '<=', $filters['created_to']);
        }

        // Sorting functionality
        $sortBy = $filters['sort_by'] ?? 'sort_order';
        $sortOrder = $filters['sort_order'] ?? 'asc';

        // Validate sort column to prevent SQL injection
        $allowedSortColumns = ['name', 'base_price', 'sort_order', 'is_active', 'created_at', 'updated_at'];
        if (!in_array($sortBy, $allowedSortColumns)) {
            $sortBy = 'sort_order';
        }

        // Validate sort order
        $sortOrder = in_array(strtolower($sortOrder), ['asc', 'desc']) ? $sortOrder : 'asc';

        $query->orderBy($sortBy, $sortOrder);

        // Use the pagination trait for consistent response format
        return $this->paginatedResponse(
            ServiceItemResource::class,
            $query,
            [],
            'Service items retrieved successfully'
        );
    }

    /**
     * Get service item by ID
     */
    public function getServiceItemById(string $serviceItemId)
    {
        $serviceItem = ServiceItem::with([
            'serviceCategory',
            'serviceItemFeatures.featureType',
            'serviceItemFeatureOptions.featureOption'
        ])
            ->where('id', $serviceItemId)
            ->first();

        if (!$serviceItem) {
            return $this->errorResponse(statusCode: 404, message: "Service item not found");
        }

        return $this->successDataResponse(
            data: $serviceItem,
            message: "Service item retrieved successfully"
        );
    }

    /**
     * Create new service item
     */
    public function createServiceItem(array $data)
    {
        DB::beginTransaction();

        try {
            // Validate service category exists
            $serviceCategory = ServiceCategory::where('id', $data['service_category_id'])->first();
            if (!$serviceCategory) {
                return $this->errorResponse(statusCode: 404, message: "Service category not found");
            }

            $serviceItem = ServiceItem::create([
                'service_category_id' => $data['service_category_id'],
                'name' => $data['name'],
                'slug' => $data['slug'] ?? Str::slug($data['name']),
                'description' => $data['description'] ?? null,
                'image' => $data['image'] ?? null,
                'base_price' => $data['base_price'] ?? 0,
                'unit' => $data['unit'] ?? 'piece',
                'is_active' => $data['is_active'] ?? true,
                'sort_order' => $data['sort_order'] ?? 0,
            ]);

            // Handle features if provided
            if (isset($data['features']) && is_array($data['features'])) {
                foreach ($data['features'] as $featureData) {
                    // Validate feature type exists
                    $featureType = FeatureType::where('id', $featureData['feature_type_id'])->first();
                    if (!$featureType) {
                        throw new \Exception("Feature type not found: {$featureData['feature_type_id']}");
                    }

                    // Create service item feature
                    $serviceItemFeature = ServiceItemFeature::create([
                        'service_item_id' => $serviceItem->id,
                        'feature_type_id' => $featureData['feature_type_id'],
                        'is_required' => $featureData['is_required'] ?? false,
                        'sort_order' => $featureData['sort_order'] ?? 0,
                    ]);

                    // Handle feature options if provided
                    if (isset($featureData['options']) && is_array($featureData['options'])) {
                        foreach ($featureData['options'] as $optionData) {
                            // Validate feature option exists
                            $featureOption = FeatureOption::where('id', $optionData['feature_option_id'])->first();
                            if (!$featureOption) {
                                throw new \Exception("Feature option not found: {$optionData['feature_option_id']}");
                            }

                            // Create service item feature option
                            ServiceItemFeatureOption::create([
                                'service_item_id' => $serviceItem->id,
                                'feature_option_id' => $optionData['feature_option_id'],
                                'is_available' => $optionData['is_available'] ?? true,
                                'price_adjustment' => $optionData['price_adjustment'] ?? 0,
                                'price_adjustment_type' => $optionData['price_adjustment_type'] ?? 'fixed',
                                'sort_order' => $optionData['sort_order'] ?? 0,
                            ]);
                        }
                    }
                }
            }

            DB::commit();

            // Reload with relationships
            $serviceItem->load([
                'serviceCategory',
                'serviceItemFeatures.featureType',
                'serviceItemFeatureOptions.featureOption'
            ]);

            return $this->successDataResponse(
                data: $serviceItem,
                message: "Service item created successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Service item creation failed: ' . $e->getMessage(), [
                'data' => $data,
                'exception' => $e,
            ]);

            return $this->errorResponse(statusCode: 500, message: "An error occurred during service item creation.");
        }
    }

    /**
     * Update service item
     */
    public function updateServiceItem(string $serviceItemId, array $data)
    {
        $serviceItem = ServiceItem::where('id', $serviceItemId)->first();

        if (!$serviceItem) {
            return $this->errorResponse(statusCode: 404, message: "Service item not found");
        }

        DB::beginTransaction();

        try {
            // Validate service category exists if provided
            if (isset($data['service_category_id'])) {
                $serviceCategory = ServiceCategory::where('id', $data['service_category_id'])->first();
                if (!$serviceCategory) {
                    return $this->errorResponse(statusCode: 404, message: "Service category not found");
                }
            }

            $serviceItem->update([
                'service_category_id' => $data['service_category_id'] ?? $serviceItem->service_category_id,
                'name' => $data['name'] ?? $serviceItem->name,
                'slug' => $data['slug'] ?? (isset($data['name']) ? Str::slug($data['name']) : $serviceItem->slug),
                'description' => $data['description'] ?? $serviceItem->description,
                'image' => $data['image'] ?? $serviceItem->image,
                'base_price' => $data['base_price'] ?? $serviceItem->base_price,
                'unit' => $data['unit'] ?? $serviceItem->unit,
                'is_active' => $data['is_active'] ?? $serviceItem->is_active,
                'sort_order' => $data['sort_order'] ?? $serviceItem->sort_order,
            ]);

            // Handle features update if provided
            if (isset($data['features']) && is_array($data['features'])) {
                // Remove existing features not in the update
                $existingFeatureIds = $serviceItem->serviceItemFeatures()->pluck('id')->toArray();
                $updatedFeatureIds = [];

                foreach ($data['features'] as $featureData) {
                    // Validate feature type exists
                    $featureType = FeatureType::where('id', $featureData['feature_type_id'])->first();
                    if (!$featureType) {
                        throw new \Exception("Feature type not found: {$featureData['feature_type_id']}");
                    }

                    if (isset($featureData['id'])) {
                        // Update existing feature
                        $serviceItemFeature = ServiceItemFeature::where('id', $featureData['id'])
                            ->where('service_item_id', $serviceItemId)
                            ->first();

                        if ($serviceItemFeature) {
                            $serviceItemFeature->update([
                                'feature_type_id' => $featureData['feature_type_id'],
                                'is_required' => $featureData['is_required'] ?? $serviceItemFeature->is_required,
                                'sort_order' => $featureData['sort_order'] ?? $serviceItemFeature->sort_order,
                            ]);
                            $updatedFeatureIds[] = $serviceItemFeature->id;
                        }

                        // Handle feature options update
                        if (isset($featureData['options']) && is_array($featureData['options'])) {
                            foreach ($featureData['options'] as $optionData) {
                                // Validate feature option exists
                                $featureOption = FeatureOption::where('id', $optionData['feature_option_id'])->first();
                                if (!$featureOption) {
                                    throw new \Exception("Feature option not found: {$optionData['feature_option_id']}");
                                }

                                if (isset($optionData['id'])) {
                                    // Update existing option
                                    $serviceItemFeatureOption = ServiceItemFeatureOption::where('id', $optionData['id'])
                                        ->where('service_item_id', $serviceItemId)
                                        ->first();

                                    if ($serviceItemFeatureOption) {
                                        $serviceItemFeatureOption->update([
                                            'is_available' => $optionData['is_available'] ?? $serviceItemFeatureOption->is_available,
                                            'price_adjustment' => $optionData['price_adjustment'] ?? $serviceItemFeatureOption->price_adjustment,
                                            'price_adjustment_type' => $optionData['price_adjustment_type'] ?? $serviceItemFeatureOption->price_adjustment_type,
                                            'sort_order' => $optionData['sort_order'] ?? $serviceItemFeatureOption->sort_order,
                                        ]);
                                    }
                                }
                            }
                        }
                    } else {
                        // Create new feature
                        $serviceItemFeature = ServiceItemFeature::create([
                            'service_item_id' => $serviceItemId,
                            'feature_type_id' => $featureData['feature_type_id'],
                            'is_required' => $featureData['is_required'] ?? false,
                            'sort_order' => $featureData['sort_order'] ?? 0,
                        ]);

                        // Handle feature options if provided
                        if (isset($featureData['options']) && is_array($featureData['options'])) {
                            foreach ($featureData['options'] as $optionData) {
                                // Validate feature option exists
                                $featureOption = FeatureOption::where('id', $optionData['feature_option_id'])->first();
                                if (!$featureOption) {
                                    throw new \Exception("Feature option not found: {$optionData['feature_option_id']}");
                                }

                                // Create service item feature option
                                ServiceItemFeatureOption::create([
                                    'service_item_id' => $serviceItemId,
                                    'feature_option_id' => $optionData['feature_option_id'],
                                    'is_available' => $optionData['is_available'] ?? true,
                                    'price_adjustment' => $optionData['price_adjustment'] ?? 0,
                                    'price_adjustment_type' => $optionData['price_adjustment_type'] ?? 'fixed',
                                    'sort_order' => $optionData['sort_order'] ?? 0,
                                ]);
                            }
                        }
                    }
                }

                // Remove features that are no longer needed
                $featuresToRemove = array_diff($existingFeatureIds, $updatedFeatureIds);
                if (!empty($featuresToRemove)) {
                    ServiceItemFeature::whereIn('id', $featuresToRemove)->delete();
                    // Also remove associated feature options
                    ServiceItemFeatureOption::whereIn('service_item_feature_id', $featuresToRemove)->delete();
                }
            }

            DB::commit();

            return $this->successDataResponse(
                data: $serviceItem->fresh()->load([
                    'serviceCategory',
                    'serviceItemFeatures.featureType',
                    'serviceItemFeatureOptions.featureOption'
                ]),
                message: "Service item updated successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Service item update failed: ' . $e->getMessage(), [
                'service_item_id' => $serviceItemId,
                'data' => $data,
                'exception' => $e,
            ]);

            return $this->errorResponse(statusCode: 500, message: "An error occurred during service item update.");
        }
    }

    /**
     * Delete service item
     */
    public function deleteServiceItem(string $serviceItemId)
    {
        $serviceItem = ServiceItem::where('id', $serviceItemId)->first();

        if (!$serviceItem) {
            return $this->errorResponse(statusCode: 404, message: "Service item not found");
        }

        DB::beginTransaction();

        try {
            // This will cascade delete features and feature options due to foreign key constraints
            $serviceItem->delete();

            DB::commit();

            return $this->successResponse(message: "Service item deleted successfully");
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Service item deletion failed: ' . $e->getMessage(), [
                'service_item_id' => $serviceItemId,
                'exception' => $e,
            ]);

            return $this->errorResponse(statusCode: 500, message: "An error occurred during service item deletion.");
        }
    }

    /**
     * Toggle service item status
     */
    public function toggleServiceItemStatus(string $serviceItemId)
    {
        $serviceItem = ServiceItem::where('id', $serviceItemId)->first();

        if (!$serviceItem) {
            return $this->errorResponse(statusCode: 404, message: "Service item not found");
        }

        DB::beginTransaction();

        try {
            $serviceItem->update([
                'is_active' => !$serviceItem->is_active,
            ]);

            DB::commit();

            return $this->successDataResponse(
                data: $serviceItem->fresh(),
                message: "Service item status updated successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Service item status toggle failed: ' . $e->getMessage(), [
                'service_item_id' => $serviceItemId,
                'exception' => $e,
            ]);

            return $this->errorResponse(statusCode: 500, message: "An error occurred during status update.");
        }
    }
}
