<?php

namespace ViartasCore\Comments\Controllers\Accounting;

use Illuminate\Http\Request;
use ViartasCore\Comments\Models\Comment;
use ViartasCore\Core\Controllers\AccountingController;

class CommentController extends AccountingController
{
    /**
     * Get a model class from model_type
     */
    protected function getModelClass(string $modelType): string
    {
        $modelMap = config('comments.model_map', []);

        if (!isset($modelMap[$modelType])) {
            abort(404, "Unknown model type: {$modelType}");
        }

        return $modelMap[$modelType];
    }

    /**
     * Display comments for specific model
     */
    public function index(Request $request, string $modelType, int $modelId)
    {
        $modelClass = $this->getModelClass($modelType);
        $model = $modelClass::findOrFail($modelId);

        $query = Comment::with(['user', 'replies.user', 'approver'])
            ->where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId);

        // Filter by status
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        // Filter by answered/unanswered
        if ($request->filled('answered')) {
            if ($request->answered === 'no') {
                $query->whereNull('parent_id')->whereDoesntHave('replies');
            } elseif ($request->answered === 'yes') {
                $query->whereNull('parent_id')->whereHas('replies');
            }
        }

        // Filter by rating
        if ($request->filled('rating')) {
            $query->where('rating', $request->rating);
        }

        // Search
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('content', 'like', "%{$search}%")
                    ->orWhere('guest_name', 'like', "%{$search}%")
                    ->orWhere('guest_email', 'like', "%{$search}%")
                    ->orWhereHas('user', function ($q) use ($search) {
                        $q->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

        // Date filter
        if ($request->filled('date_from')) {
            $query->whereDate('created_at', '>=', $request->date_from);
        }
        if ($request->filled('date_to')) {
            $query->whereDate('created_at', '<=', $request->date_to);
        }

        // Sort
        $sort = $request->get('sort', 'created_at-desc');
        [$sortField, $sortDirection] = explode('-', $sort);
        $query->orderBy($sortField, $sortDirection);

        // Get root comments for tree view
        $rootQuery = clone $query;
        $rootComments = $rootQuery->root()->with('allReplies.user')->paginate(config('comments.per_page', 20));

        // Stats
        $stats = [
            'total' => Comment::where('commentable_type', $modelClass)->where('commentable_id', $modelId)->count(),
            'pending' => Comment::where('commentable_type', $modelClass)->where('commentable_id', $modelId)->pending()->count(),
            'approved' => Comment::where('commentable_type', $modelClass)->where('commentable_id', $modelId)->approved()->count(),
            'unanswered' => Comment::where('commentable_type', $modelClass)->where('commentable_id', $modelId)->unanswered()->count(),
            'average_rating' => Comment::where('commentable_type', $modelClass)->where('commentable_id', $modelId)->approved()->whereNotNull('rating')->avg('rating'),
        ];

        return theme_view('accounting.comments.index', [
            'comments' => $rootComments,
            'modelType' => $modelType,
            'modelId' => $modelId,
            'model' => $model,
            'element' => $model,
            'stats' => $stats,
        ]);
    }

    /**
     * Get single comment details
     */
    public function show(string $modelType, int $modelId, int $id)
    {
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::with(['user', 'allReplies.user', 'approver', 'parent'])
            ->where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        return response()->json([
            'success' => true,
            'comment' => $this->formatCommentResponse($comment, true),
        ]);
    }

    /**
     * Store a new comment (admin reply)
     */
    public function store(Request $request, string $modelType, int $modelId)
    {
        $request->validate([
            'content' => 'required|string|max:5000',
            'parent_id' => 'nullable|integer|exists:comments,id',
        ]);

        $modelClass = $this->getModelClass($modelType);
        $model = $modelClass::findOrFail($modelId);

        $comment = Comment::create([
            'commentable_type' => $modelClass,
            'commentable_id' => $modelId,
            'parent_id' => $request->parent_id,
            'user_id' => auth()->id(),
            'content' => $request->content,
            'status' => Comment::STATUS_APPROVED,
            'is_approved' => true,
            'approved_at' => now(),
            'approved_by' => auth()->id(),
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
        ]);

        $comment->load('user');

        return response()->json([
            'success' => true,
            'message' => __('comments.reply_success'),
            'comment' => $this->formatCommentResponse($comment),
        ]);
    }

    /**
     * Update comment
     */
    public function update(Request $request, string $modelType, int $modelId, $id)
    {
        $id = (int) $id;
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        $request->validate([
            'content' => 'sometimes|required|string|max:5000',
            'status' => 'sometimes|in:pending,approved,rejected,spam',
            'rating' => 'sometimes|nullable|integer|min:1|max:5',
        ]);

        if ($request->has('content')) {
            $comment->content = $request->content;
        }

        if ($request->has('status')) {
            $comment->status = $request->status;
            $comment->is_approved = $request->status === Comment::STATUS_APPROVED;

            if ($request->status === Comment::STATUS_APPROVED && !$comment->approved_at) {
                $comment->approved_at = now();
                $comment->approved_by = auth()->id();
            }
        }

        if ($request->has('rating')) {
            $comment->rating = $request->rating;
        }

        $comment->save();

        return response()->json([
            'success' => true,
            'message' => __('comments.update_success'),
            'comment' => $this->formatCommentResponse($comment),
        ]);
    }

    /**
     * Approve comment
     */
    public function approve(Request $request, string $modelType, int $modelId, int $id)
    {
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        $comment->approve(auth()->id());

        return response()->json([
            'success' => true,
            'message' => __('comments.approve_success'),
            'comment' => $this->formatCommentResponse($comment),
        ]);
    }

    /**
     * Reject comment
     */
    public function reject(Request $request, string $modelType, int $modelId, int $id)
    {
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        $comment->reject();

        return response()->json([
            'success' => true,
            'message' => __('comments.reject_success'),
            'comment' => $this->formatCommentResponse($comment),
        ]);
    }

    /**
     * Mark as spam
     */
    public function spam(Request $request, string $modelType, int $modelId, int $id)
    {
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        $comment->markAsSpam();

        return response()->json([
            'success' => true,
            'message' => __('comments.spam_success'),
        ]);
    }

    /**
     * Bulk action
     */
    public function bulk(Request $request, string $modelType, int $modelId)
    {
        $request->validate([
            'ids' => 'required|array',
            'ids.*' => 'integer',
            'action' => 'required|in:approve,reject,spam,delete',
        ]);

        $modelClass = $this->getModelClass($modelType);

        $comments = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->whereIn('id', $request->ids)
            ->get();

        $count = 0;
        foreach ($comments as $comment) {
            switch ($request->action) {
                case 'approve':
                    $comment->approve(auth()->id());
                    break;
                case 'reject':
                    $comment->reject();
                    break;
                case 'spam':
                    $comment->markAsSpam();
                    break;
                case 'delete':
                    $comment->delete();
                    break;
            }
            $count++;
        }

        return response()->json([
            'success' => true,
            'message' => __('comments.bulk_success', ['count' => $count]),
            'affected' => $count,
        ]);
    }

    /**
     * Delete comment
     */
    public function destroy(string $modelType, int $modelId, int $id)
    {
        $modelClass = $this->getModelClass($modelType);

        $comment = Comment::where('commentable_type', $modelClass)
            ->where('commentable_id', $modelId)
            ->findOrFail($id);

        // Delete all replies too
        $comment->replies()->delete();
        $comment->delete();

        return response()->json([
            'success' => true,
            'message' => __('comments.delete_success'),
        ]);
    }

    /**
     * Format comment for response
     */
    protected function formatCommentResponse(Comment $comment, bool $detailed = false): array
    {
        $response = [
            'id' => $comment->id,
            'content' => $comment->content,
            'author_name' => $comment->author_name,
            'author_email' => $comment->author_email,
            'author_initials' => $comment->author_initials,
            'user_id' => $comment->user_id,
            'rating' => $comment->rating,
            'status' => $comment->status,
            'is_approved' => $comment->is_approved,
            'has_replies' => $comment->hasReplies(),
            'replies_count' => $comment->replies()->count(),
            'created_at' => $comment->created_at->format('M d, Y H:i'),
            'created_at_human' => $comment->created_at->diffForHumans(),
        ];

        if ($detailed) {
            $response['parent_id'] = $comment->parent_id;
            $response['approved_at'] = $comment->approved_at?->format('M d, Y H:i');
            $response['approver'] = $comment->approver ? [
                'id' => $comment->approver->id,
                'name' => $comment->approver->name,
            ] : null;
            $response['ip_address'] = $comment->ip_address;
            $response['user_agent'] = $comment->user_agent;
            $response['metadata'] = $comment->metadata;
            $response['replies'] = $comment->allReplies->map(fn($r) => $this->formatCommentResponse($r))->toArray();
        }

        return $response;
    }
}
