<?php

namespace App\Repositories;

use Abedin\Maker\Repositories\Repository;
use App\Enums\PostStatus;
use App\Models\SellingPost;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage;

class  SellingPostRepository extends Repository
{
    public static function model()
    {
        return SellingPost::class;
    }


    public static function getByStatus($status = null, $perPage = 0, $search = null)
    {
        $query = self::query()
            ->when($status, function ($query) use ($status) {
                $query->where('status', $status);
            })
            ->when($search, function ($query) use ($search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'LIKE', "%{$search}%")
                        ->orWhere('contact_number', 'LIKE', "%{$search}%")
                        ->orWhereHas('user', function ($q2) use ($search) {
                            $q2->where('name', 'LIKE', "%{$search}%");
                        })
                        ->orWhereHas('brand', function ($q2) use ($search) {
                            $q2->where('name', 'LIKE', "%{$search}%");
                        });
                });
            })
            ->orderBy('created_at', 'desc'); // Added descending order

        // Paginate only at the end
        return $perPage ? $query->withTrashed()->paginate($perPage)->withQueryString() : $query->withTrashed()->get();
    }

    public static function countByStatus($status = null)
    {
        return $status ? self::model()::where('status', $status)->count() : self::model()::count();
    }

    public static function getTrashed($perPage = 10)
    {
        return SellingPost::onlyTrashed()->paginate($perPage);
    }


    public static function updatePostWithMedia(SellingPost $post, array $data): SellingPost
    {
        // Basic info
        $post->name = $data['name'] ?? $post->name;
        $post->conditions = $data['condition'] ?? $post->conditions;
        $post->asking_price = $data['price'] ?? $post->asking_price;
        $post->sold_price = $data['sold_price'] ?? $post->sold_price;
        $post->contact_number = $data['phone'] ?? $post->contact_number;
        $post->email = $data['email'] ?? $post->email;
        $post->description = $data['description'] ?? $post->description;
        $post->latitude = $data['latitude'] ?? $post->latitude;
        $post->longitude = $data['longitude'] ?? $post->longitude;
        $post->warranty_left = $data['warranty'] ?? $post->warranty_left;
        $post->model = $data['model'] ?? $post->model;
        $post->color_code = $data['color'] ?? $post->color_code;
        $post->is_negotiable = !empty($data['negotiable']);
        $post->status = $data['status'] ?? $post->status;
        $post->is_sold = !empty($data['is_sold']);
        $post->brand_id = $data['brand'] ?? $post->brand_id;

        $post->save();


        if (!empty($data['thumbnail'])) {
            $media = MediaRepository::storeByRequest($data['thumbnail'], 'thumbnails');
            $post->media_id = $media->id;
            $post->save();

            if (!$post->thumbnails->contains($media->id)) {
                $post->thumbnails()->attach($media->id, ['default' => true]);
            }
        }


        // Remove selected images
        foreach ($data['remove_additional_images'] ?? [] as $src) {
            $media = $post->thumbnails()->where('src', $src)->first();
            if ($media) {
                $post->thumbnails()->detach($media->id);
                // optionally delete from storage: Storage::delete($media->src);
            }
        }


        $existingImages = $data['existing_additional_images'] ?? [];
        $currentImages = $post->thumbnails->pluck('src')->toArray();


        foreach ($currentImages as $src) {
            if (!in_array($src, $existingImages) && empty($data['remove_additional_images'])) {
                $media = $post->thumbnails()->where('src', $src)->first();
                if ($media) {
                    $post->thumbnails()->detach($media->id);
                }
            }
        }


        foreach ($data['additional_images'] ?? [] as $file) {
            $media = MediaRepository::storeByRequest($file, 'additional_images');
            $post->thumbnails()->attach($media->id, ['default' => false]);
        }


        $categories = array_filter([$data['category'] ?? null, $data['subcategory'] ?? null]);
        $post->categories()->sync($categories);


        if (!empty($data['attributes']) && is_array($data['attributes'])) {
            $post->attributes()->sync($data['attributes']);
        } else {
            $post->attributes()->detach();
        }

        return $post;
    }

    // ================= NEW METHODS =================

    public static function getByIdWithRelations($id)
    {
        return self::query()->with(['user', 'brand', 'thumbnails'])->findOrFail($id);
    }

    public static function getRelatedProducts($product)
    {
        return self::query()
            ->where('id', '!=', $product->id)
            ->where('brand_id', $product->brand_id)
            ->where('status', 'Approve')
            ->limit(4)
            ->get();
    }

    public static function getDistinctConditions()
    {
        return self::query()->select('conditions')->distinct()->pluck('conditions');
    }

    public static function getLocationsWithCount()
    {
        $addresses = SellingPostRepository::query()->pluck('location'); // pura address

        $counts = [];

        foreach ($addresses as $address) {
            $location = trim($address); // pura string
            if ($location !== '') {
                // duplicate remove + count
                $counts[$location] = isset($counts[$location]) ? $counts[$location] + 1 : 1;
            }
        }

        // alphabetical sort optional
        ksort($counts);

        return collect($counts);
    }

    public static function getBrandsWithCount()
    {
        return self::query()
            ->where('status', PostStatus::Approve->value)
            ->where('is_sold', false)
            ->with('brand')
            ->whereHas('brand', function($query){
                $query->where('is_active', true);
            })
            ->get()
            ->groupBy(fn($post) => $post->brand->name ?? 'Unknown')
            ->map(fn($posts, $brand) => $posts->count());
    }
    public static function getDateFiltersWithCount()
    {
        $now = now();

        $ranges = [
            'All Time' => null,
            'Today' => ['date', $now->copy()->toDateString()],
            'Within 1 Week' => ['from', $now->copy()->subWeek()],
            'Within 2 Weeks' => ['from', $now->copy()->subWeeks(2)],
            'Within 1 Month' => ['from', $now->copy()->subMonth()],
        ];

        $result = [];

        foreach ($ranges as $label => $range) {
            $query = self::query()
                ->where('status', PostStatus::Approve->value)
                ->where('is_sold', false);

            if ($range) {
                [$type, $value] = $range;

                $type === 'date'
                    ? $query->whereDate('created_at', $value)
                    : $query->where('created_at', '>=', $value);
            }

            $result[$label] = $query->count();
        }

        return $result;
    }

    public static function getDealMethods()
    {
        return self::query()
            ->select('deal_method')
            ->distinct()
            ->pluck('deal_method')
            ->filter();
    }
    public static function getBoostedProducts($limit = 10)
    {
        $query = self::query()
            ->with(['user', 'brand', 'thumbnails', 'boosts' => function ($q) {
                $q->where('expired_at', '>', now());
            }])
            ->whereHas('boosts', function ($q) {
                $q->where('expired_at', '>', now());
            })
            ->where('is_sold', false)
            ->latest();

        return $limit ? $query->take($limit)->get() : $query->get();
    }


    public static function getNewProducts($limit = 8)
    {
        return self::query()
            ->with(['user', 'brand', 'defaultThumbnail']) // default only
            ->where('status', 'Approve')
            ->latest()
            ->take($limit)
            ->get();
    }

    public static function trashedByUser($userId)
    {
        return self::query()->onlyTrashed()->where('user_id', $userId);
    }

    public static function restoreByUser($postId, $userId)
    {
        $post = self::query()->onlyTrashed()
            ->where('user_id', $userId)
            ->findOrFail($postId);

        $post->restore();

        return $post;
    }

    public static function storeByRequest(Request $request, int $userId): SellingPost
    {
        // 1️ Create main post
        $post = SellingPost::create([
            'name'           => $request->name,
            'conditions'     => $request->condition,
            'asking_price'   => $request->price,
            'contact_number' => $request->phone,
            'email'          => $request->email,
            'description'    => $request->description,
            'latitude'       => $request->latitude ?? null,
            'longitude'      => $request->longitude ?? null,
            'location'       => $request->location ?? null,
            'brand_id'       => $request->brand ?? null,
            'warranty_left'  => $request->warranty ?? null,
            'model'          => $request->model ?? null,
            'color_code'     => $request->color ?? null,
           'is_negotiable' => (bool) $request->negotiable,
            'status'         => 'Pending',
            'user_id'        => $userId,
        ]);

        // 2️Handle thumbnail
        if ($request->hasFile('thumbnail')) {
            $media = MediaRepository::storeByRequest($request->file('thumbnail'), 'thumbnails');
            $post->update(['media_id' => $media->id]);
        }

        // 3️ Handle additional images
        if ($request->hasFile('additional_images')) {
            foreach ($request->file('additional_images') as $file) {
                $media = MediaRepository::storeByRequest($file, 'additional_images');
                $post->thumbnails()->attach($media->id, ['default' => false]);
            }
        }

        // 4️ Handle categories
        $categories = array_filter([$request->category, $request->subcategory]);
        if (!empty($categories)) {
            $post->categories()->sync($categories);
        }

        // 5️Handle attributes
        if (!empty($request->attributes) && is_array($request->attributes)) {
            $post->attributes()->sync($request->attributes);
        }

        return $post;
    }


    public static function updateByRequest(SellingPost $post, Request $request): SellingPost
    {

        $post->name = $request->name;
        $post->conditions = $request->condition;
        $post->asking_price = $request->price;
        $post->contact_number = $request->phone ?? null;
        $post->email = $request->email ?? null;
        $post->description = $request->description;
        $post->location = $request->location ?? $post->location;
        $post->latitude = $request->latitude ?? $post->latitude;
        $post->longitude = $request->longitude ?? $post->longitude;
        $post->brand_id = $request->brand ?? null;
        $post->warranty_left = $request->warranty ?? null;
        $post->model = $request->model ?? null;
        $post->color_code = $request->color ?? null;
        $post->is_negotiable = $request->has('negotiable');
        $post->status = 'Pending';
        $post->save();


        if ($request->hasFile('thumbnail')) {
            $oldMedia = $post->profile ?? null;

            if ($oldMedia && Storage::disk('public')->exists($oldMedia->src)) {
                Storage::disk('public')->delete($oldMedia->src);
            }

            $media = MediaRepository::storeByRequest($request->file('thumbnail'), 'thumbnails');
            $post->media_id = $media->id;
            $post->save();
        }


        $existingImages = $request->existing_additional_images ?? [];
        $existingMediaIds = [];

        foreach ($existingImages as $src) {
            $media = $post->thumbnails()->where('src', $src)->first();
            if ($media) $existingMediaIds[] = $media->id;
        }


        if (!empty($request->remove_additional_images) && is_array($request->remove_additional_images)) {
            foreach ($request->remove_additional_images as $src) {
                $media = $post->thumbnails()->where('src', $src)->first();
                if ($media) {
                    $post->thumbnails()->detach($media->id);
                    if (Storage::disk('public')->exists($media->src)) {
                        Storage::disk('public')->delete($media->src);
                    }
                }
            }
        }


        $post->thumbnails()->syncWithoutDetaching($existingMediaIds);


        if ($request->hasFile('additional_images')) {
            foreach ($request->file('additional_images') as $file) {
                $media = MediaRepository::storeByRequest($file, 'additional_images');
                $post->thumbnails()->attach($media->id, ['default' => false]);
            }
        }


        $categories = array_filter([$request->category, $request->subcategory]);
        $post->categories()->sync($categories);


        if (!empty($request->attributes) && is_array($request->attributes)) {
            $post->attributes()->sync($request->attributes);
        }

        return $post;
    }

    public static function makeCopypost(int $id): SellingPost
    {
        // Find the original product
        $original = self::findOrFail($id);

        // Clone the main attributes
        $copy = $original->replicate();
        $copy->name = $original->name . ' (Copy)';
        $copy->status = 'Pending';
        $copy->is_sold = 0;
        $copy->sold_price = null;
        $copy->created_at = now();
        $copy->updated_at = now();
        $copy->save();

        // Clone categories
        $categoryIds = $original->categories()->pluck('id')->toArray();
        if (!empty($categoryIds)) {
            $copy->categories()->attach($categoryIds);
        }

        // Clone attributes
        $attributeIds = $original->attributes()->pluck('id')->toArray();
        if (!empty($attributeIds)) {
            $copy->attributes()->attach($attributeIds);
        }

        // Clone main thumbnail
        if ($original->media_id) {
            $originalMedia = $original->profile; // Assuming 'profile' relationship returns Media model

            if ($originalMedia && Storage::disk('public')->exists($originalMedia->src)) {
                // Duplicate the file
                $filePath = $originalMedia->src;
                $newFileName = 'thumbnails/' . uniqid() . '-' . basename($filePath);
                Storage::disk('public')->copy($filePath, $newFileName);

                // Create a new Media record
                $newMedia = $originalMedia->replicate();
                $newMedia->src = $newFileName;
                $newMedia->save();

                $copy->media_id = $newMedia->id;
                $copy->save();
            }
        }

        // Clone additional images
        $originalMediaIds = $original->thumbnails->pluck('id')->toArray();
        if (!empty($originalMediaIds)) {
            $copy->thumbnails()->attach($originalMediaIds);
        }

        return $copy;
    }

    public static function getSellingPostReport()
    {
        $year = now()->format('Y');
        $month = now()->format('m');

        // sold posts
        $posts = self::query()->where('is_sold', 1);

        // Monthly
        if (request()->type == 'monthly') {
            $posts = $posts->whereMonth('updated_at', $month)
                ->whereYear('updated_at', $year)->get();

            $daysInMonth = Carbon::create($year, $month)->daysInMonth;
            $dailyCounts = array_fill(1, $daysInMonth, 0);

            foreach ($posts as $post) {
                $day = Carbon::parse($post->updated_at)->day;
                $dailyCounts[$day]++;
            }

            $filterPosts = [
                'labels' => array_map(fn($d) => str_pad($d, 2, '0', STR_PAD_LEFT), array_keys($dailyCounts)),
                'values' => array_values($dailyCounts),
            ];

            // Yearly
        } elseif (request()->type == 'yearly') {
            $posts = $posts->whereYear('updated_at', $year)->get();

            $months = [
                1 => 'Jan',
                2 => 'Feb',
                3 => 'Mar',
                4 => 'Apr',
                5 => 'May',
                6 => 'Jun',
                7 => 'Jul',
                8 => 'Aug',
                9 => 'Sep',
                10 => 'Oct',
                11 => 'Nov',
                12 => 'Dec'
            ];
            $monthlyCounts = array_fill_keys(array_values($months), 0);

            foreach ($posts as $post) {
                $monthNum = Carbon::parse($post->updated_at)->month;
                $monthName = $months[$monthNum];
                $monthlyCounts[$monthName]++;
            }

            $filterPosts = [
                'labels' => array_keys($monthlyCounts),
                'values' => array_values($monthlyCounts),
            ];

            // Daily
        } else {
            $posts = request()->type && request()->type != 'daily'
                ? $posts->whereDate('updated_at', request()->type)->get()
                : $posts->whereDate('updated_at', now())->get();

            $filterPosts = [
                'labels' => ['Today'],
                'values' => [$posts->count()],
            ];
        }

        return $filterPosts;
    }

    public static function getNearProducts($request)
    {
        $latitude = $request->input('latitude');
        $longitude = $request->input('longitude');

        if (!$latitude || !$longitude) {
            return collect();
        }

        $products = self::query()
            ->where('status', 'Approve')
            ->whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->selectRaw(
                '*, ( 6371 * acos( cos( radians(?) ) * cos( radians(latitude) )
                * cos( radians(longitude) - radians(?) ) + sin( radians(?) ) * sin( radians(latitude) ) ) ) AS distance',
                [$latitude, $longitude, $latitude]
            )
            ->orderBy('distance', 'ASC')

            ->take(10)
            ->get();

        return $products;
    }

    public static function filterProducts($request, $routeCategoryId = null)
    {
        $query = self::query()->with(['user', 'brand', 'thumbnails'])
            ->where('status', PostStatus::Approve->value)
            ->where('is_sold', false);

        //  Search filter
        if ($request->filled('product_search')) {
            $search = $request->query('product_search');
            $query->where(function ($q) use ($search) {
                $q->where('name', 'LIKE', "%{$search}%")
                    ->orWhere('description', 'LIKE', "%{$search}%");
            });
        }

        // Condition filter
        if ($request->filled('conditions')) {
            $conditions = $request->input('conditions');
            if (!is_array($conditions)) {
                $conditions = explode(',', $conditions);
            }
            $query->whereIn('conditions', $conditions);
        }


        if ($request->filled('location')) {
            $locations = is_array($request->location) ? $request->location : [$request->location];

            $query->whereIn('location', $locations);
        }



        // 🏷 Brand filter
        if ($request->filled('brand')) {
            $brands = (array) $request->input('brand');
            $query->whereHas('brand', function ($q) use ($brands) {
                $q->whereIn('name', $brands);
            });
        }

        //  Date filter (array or single)
        if ($request->filled('date')) {
            $dateFilters = (array) $request->input('date');

            if (!in_array('All Time', $dateFilters, true)) {
                $query->where(function ($q) use ($dateFilters) {
                    foreach ($dateFilters as $dateFilter) {
                        match ($dateFilter) {
                            'Today' => $q->orWhereDate('created_at', today()),
                            'Within 1 Week', 'Last 7 days' => $q->orWhere('created_at', '>=', now()->subWeek()),
                            'Within 2 Weeks' => $q->orWhere('created_at', '>=', now()->subWeeks(2)),
                            'Within 1 Month', 'Last 30 days' => $q->orWhere('created_at', '>=', now()->subMonth()),
                            'Last 24 hours' => $q->orWhere('created_at', '>=', now()->subHours(24)),
                            default => null,
                        };
                    }
                });
            }
        }

        //  Category filter
        $categoryId = $routeCategoryId ?: $request->input('category');

        if (!empty($categoryId)) {
            $categoryIds = CategoryRepository::query()
                ->where('parent_id', $categoryId)
                ->pluck('id')
                ->push($categoryId);

            $query->whereHas('categories', function ($q) use ($categoryIds) {
                $q->whereIn('id', $categoryIds);
            });
        }

        //  Price filter
        if ($request->filled('min_price') && $request->filled('max_price')) {
            $query->whereBetween(
                'asking_price',
                [(float) $request->min_price, (float) $request->max_price]
            );
        }

        // ↕ Price sort
        if ($request->price_sort == 'low_high') {
            $query->orderBy('asking_price', 'asc');
        } elseif ($request->price_sort == 'high_low') {
            $query->orderBy('asking_price', 'desc');
        } elseif ($request->price_sort == 'recent') {
            $query->orderBy('created_at', 'desc');
        }

        return $query;
    }




    // Pruducts Reports

    public static function getProductsByDateRange($range, $request)
    {
        return self::query()
            ->when($range == 'today', fn($q) => $q->whereDate('created_at', Carbon::today()))
            ->when($range == 'yesterday', fn($q) => $q->whereDate('created_at', Carbon::yesterday()))
            ->when($range == 'last_7_days', fn($q) => $q->whereBetween('created_at',[Carbon::now()->subDays(6)->startOfDay(), Carbon::now()->endOfDay()]))                                                                                 // Last 7 days
            ->when($range == 'last_30_days', fn($q) => $q->whereBetween('created_at',[Carbon::now()->subDays(29)->startOfDay(), Carbon::now()->endOfDay()]))                                                                                 // Last 30 days
            ->when($range == 'custom' && $request->filled(['start_date','end_date']), fn($q) => $q->whereBetween(
                'created_at',
                [
                    Carbon::parse($request->start_date)->startOfDay(),
                    Carbon::parse($request->end_date)->endOfDay()
                ]
            ))->orderByDesc('created_at')->get();
    }


    public static function getDateRangeTitle($range, $request)
    {
        return match($range) {
            'today' => 'Today - ' . Carbon::today()->format('d M Y'),
            'yesterday' => 'Yesterday - ' . Carbon::yesterday()->format('d M Y'),
            'last_7_days' => 'Last 7 Days (' . Carbon::now()->subDays(6)->format('d M Y') . ' - ' . Carbon::now()->format('d M Y') . ')',
            'last_30_days' => 'Last 30 Days (' . Carbon::now()->subDays(29)->format('d M Y') . ' - ' . Carbon::now()->format('d M Y') . ')',
            'custom' => $request->filled(['start_date', 'end_date'])
                ? Carbon::parse($request->start_date)->format('d M Y') . ' - ' . Carbon::parse($request->end_date)->format('d M Y')
                : 'Custom Range',
            default => 'All Time',
        };
    }


    public static function getReportStats($products)
    {
        return [
            'total' => $products->count(),
            'approved' => $products->where('status', PostStatus::Approve->value)->count(),
            'pending' => $products->where('status', PostStatus::Pending->value)->count(),
            'blocked' => $products->where('status', PostStatus::InReview->value)->count(),
            'Reject' => $products->where('status', PostStatus::Reject->value)->count(),
            'Soled' => $products->where('status', PostStatus::Soled->value)->count(),
            'Cancel' => $products->where('status', PostStatus::Cancel->value)->count(),
        ];
    }

}
