<?php

namespace App\Service\Admin;

use App\Http\Resources\BlogResource;
use App\Models\Blog;
use App\Models\BlogCategory;
use App\Models\User;
use App\Traits\JsonResponseTrait;
use App\Traits\PaginationResponseTrait;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Log;

class BlogService
{
    use JsonResponseTrait, PaginationResponseTrait;

    /**
     * Generate unique slug from title
     */
    private function generateUniqueSlug(string $title, string $excludeId = null): string
    {
        $slug = Str::slug($title);
        $originalSlug = $slug;
        $counter = 1;

        // Check if slug exists and exclude current blog ID during update
        $query = Blog::where('slug', $slug);
        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        while ($query->exists()) {
            $slug = $originalSlug . '-' . $counter;
            $query = Blog::where('slug', $slug);
            if ($excludeId) {
                $query->where('id', '!=', $excludeId);
            }
            $counter++;
        }

        return $slug;
    }

    /**
     * Get all blogs with search, sort, filter and pagination
     */
    public function getAllBlogs(array $filters = [])
    {
        $query = Blog::with(['category', 'author']);

        // Search functionality
        if (!empty($filters['search'])) {
            $searchTerm = $filters['search'];
            $query->where(function ($q) use ($searchTerm) {
                $q->where('title', 'LIKE', "%{$searchTerm}%")
                    ->orWhere('content', 'LIKE', "%{$searchTerm}%")
                    ->orWhere('excerpt', 'LIKE', "%{$searchTerm}%")
                    ->orWhere('slug', 'LIKE', "%{$searchTerm}%")
                    ->orWhereHas('category', function ($categoryQuery) use ($searchTerm) {
                        $categoryQuery->where('name', 'LIKE', "%{$searchTerm}%");
                    })
                    ->orWhereHas('author', function ($authorQuery) use ($searchTerm) {
                        $authorQuery->where('firstname', 'LIKE', "%{$searchTerm}%")
                            ->orWhere('lastname', 'LIKE', "%{$searchTerm}%");
                    });
            });
        }

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

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

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

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

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

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

        // Date range filtering for created_at
        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'] ?? 'created_at';
        $sortOrder = $filters['sort_order'] ?? 'desc';

        // Validate sort column to prevent SQL injection
        $allowedSortColumns = ['title', 'status', 'is_featured', 'published_at', 'created_at', 'updated_at', 'view_count'];
        if (!in_array($sortBy, $allowedSortColumns)) {
            $sortBy = 'created_at';
        }

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

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

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

    /**
     * Get blog by ID
     */
    public function getBlogById(string $blogId)
    {
        $blog = Blog::where('id', $blogId)->with(['category', 'author'])->first();

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

        return $this->successDataResponse(
            data: $blog,
            message: "Blog retrieved successfully"
        );
    }

    /**
     * Create new blog
     */
    public function createBlog(array $data, User $authUser)
    {
        if (!$authUser) {
            return $this->errorResponse(statusCode: 401, message: "Unauthorized user access");
        }
        $userId = $authUser->id;

        DB::beginTransaction();

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

            // Use authenticated user's ID if author_id not provided
            $authorId = $data['author_id'] ?? $userId;

            $blog = Blog::create([
                'author_id' => $authorId,
                'title' => $data['title'],
                'header' => $data['header'] ?? null,
                'image_url' => $data['image_url'] ?? null,
                'content' => $data['content'],
                'category_id' => $data['category_id'],
                'read_count' => $data['read_count'] ?? 0,
                'minute_read' => $data['minute_read'] ?? 0,
                'slug' => $this->generateUniqueSlug($data['title']),
                'status' => $data['status'] ?? true,
            ]);

            DB::commit();

            return $this->successDataResponse(
                data: $blog->load(['category', 'author']),
                message: "Blog created successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

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

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

    /**
     * Update blog
     */
    public function updateBlog(string $blogId, array $data, User $authUser)
    {
        if (!$authUser) {
            return $this->errorResponse(statusCode: 401, message: "Unauthorized user access");
        }
        $userId = $authUser->id;

        $blog = Blog::where('id', $blogId)->first();

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

        // Validate category exists if provided
        if (isset($data['category_id'])) {
            $category = BlogCategory::where('id', $data['category_id'])->first();
            if (!$category) {
                return $this->errorResponse(statusCode: 404, message: "Blog category not found");
            }
        }

        DB::beginTransaction();

        try {
            // Use authenticated user's ID if author_id not provided
            $authorId = $data['author_id'] ?? $blog->author_id;

            // Generate new slug if title is updated
            $newSlug = null;
            if (isset($data['title'])) {
                $newSlug = $this->generateUniqueSlug($data['title'], $blogId);
            }

            $blog->update([
                'author_id' => $authorId,
                'title' => $data['title'] ?? $blog->title,
                'header' => $data['header'] ?? $blog->header,
                'image_url' => $data['image_url'] ?? $blog->image_url,
                'content' => $data['content'] ?? $blog->content,
                'category_id' => $data['category_id'] ?? $blog->category_id,
                'read_count' => $data['read_count'] ?? $blog->read_count,
                'minute_read' => $data['minute_read'] ?? $blog->minute_read,
                'slug' => $newSlug ?? $blog->slug,
                'status' => $data['status'] ?? $blog->status,
            ]);

            DB::commit();

            return $this->successDataResponse(
                data: $blog->fresh()->load(['category', 'author']),
                message: "Blog updated successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Blog update failed: ' . $e->getMessage(), [
                'blog_id' => $blogId,
                'data' => $data,
                'exception' => $e,
            ]);

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

    /**
     * Delete blog
     */
    public function deleteBlog(string $blogId)
    {
        $blog = Blog::where('id', $blogId)->first();

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

        DB::beginTransaction();

        try {
            $blog->delete();

            DB::commit();

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

            Log::error('Blog deletion failed: ' . $e->getMessage(), [
                'blog_id' => $blogId,
                'exception' => $e,
            ]);

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

    /**
     * Toggle blog status
     */
    public function toggleBlogStatus(string $blogId)
    {
        $blog = Blog::where('id', $blogId)->first();

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

        DB::beginTransaction();

        try {
            $blog->update([
                'status' => !$blog->status,
            ]);

            DB::commit();

            return $this->successDataResponse(
                data: $blog->fresh()->load(['category', 'author']),
                message: "Blog status updated successfully"
            );
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Blog status toggle failed: ' . $e->getMessage(), [
                'blog_id' => $blogId,
                'exception' => $e,
            ]);

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