<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Article;
use App\Models\Category;
use App\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Inertia\Inertia;

class ArticleBaseController extends Controller
{
    private int $_type = 0;

    private string $_module = 'mattock';

    private array $_pipopaArticleSlugBlock = [
        'features',
        'pricing',
        'chat-demo',
        'company',
        'contact',
        'help',
        'api',
        'privacy',
        'terms',
        'security',
        'status',
        'careers',
        'doc',
        'articles',
        'category',
        'tag',
    ];

    public function __construct($module = null)
    {
        if ($module == 'pipopa') {
            $this->_type = 1;
            $this->_module = 'pipopa';
        }
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $search = $request->input('search');
        $status = $request->input('status');
        $category = $request->input('category');
        $perPage = $request->input('per_page', 10);

        $articles = Article::with(['user', 'primaryCategory', 'categories', 'tags'])
            ->where('type', $this->_type)
            ->when($search, function ($query, $search) {
                return $query->where('title', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%");
            })
            ->when($status, function ($query, $status) {
                return $query->where('status', $status);
            })
            ->when($category, function ($query, $category) {
                return $query->whereHas('categories', function ($q) use ($category) {
                    $q->where('categories.id', $category);
                });
            });

        // Check permissions
        $user = Auth::user();
        if (($this->_type == 0 && ! $user->can('articles.mattock.view') && $user->can('articles.mattock.owner.view')) ||
            ($this->_type == 1 && ! $user->can('articles.pipopa.view') && $user->can('articles.pipopa.owner.view'))) {
            $articles->where('user_id', $user->id);
        }

        $articles = $articles->orderBy('created_at', 'desc')->paginate($perPage);
        $categories = Category::where('type', $this->_type)->get();
        $statusOptions = ['draft', 'pending', 'private', 'future', 'publish'];

        return Inertia::render("admin/{$this->_module}/articles/Index", [
            'articles'      => $articles,
            'categories'    => $categories,
            'statusOptions' => $statusOptions,
            'filters'       => [
                'search'   => $search,
                'status'   => $status,
                'category' => $category,
                'per_page' => $perPage,
            ],
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $categories = Category::where('type', $this->_type)->get();
        $tags = Tag::where('type', $this->_type)->get();

        return Inertia::render("admin/{$this->_module}/articles/Create", [
            'categories' => $categories,
            'tags'       => $tags,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'               => 'required|string|max:255',
            'slug'                => 'nullable|string|max:255',
            'image'               => 'nullable|string|max:500',
            'description'         => 'nullable|string|max:500',
            'content'             => 'nullable|string',
            'status'              => 'required',
            'categories'          => 'nullable|array',
            'categories.*'        => 'exists:categories,id',
            'primary_category_id' => 'nullable|exists:categories,id',
            'tags'                => 'nullable|array',
            'tags.*'              => 'string|max:255',
        ]);

        // Check permissions
        $user = Auth::user();
        if (($this->_type == 0 && ! $user->can('articles.mattock.create')) ||
            ($this->_type == 1 && ! $user->can('articles.pipopa.create'))) {
            return redirect()->route('admin.pages.404');
        }

        $checkArticleTitle = Article::where('type', $this->_type)
            ->where('title', $validated['title'])
            ->exists();
        if ($checkArticleTitle) {
            return back()->withErrors(['title' => 'Title already exists.']);
        }

        if (isset($validated['slug']) && $validated['slug'] != '') {
            // Sanitize the slug
            $validated['slug'] = $this->sanitizeSlug($validated['slug']);

            $checkArticleSlug = Article::where('type', $this->_type)->where('slug', $validated['slug'])->exists();
            if ($checkArticleSlug || ($this->_type == 1 && in_array($validated['slug'], $this->_pipopaArticleSlugBlock))) {
                return back()->withErrors(['slug' => 'URL already exists.']);
            }
        } else {
            $slugPrefix = 0;
            do {
                $slug = Str::slug($this->convertJapaneseToRomaji(trim($validated['title'])));
                if ($slugPrefix > 0) {
                    $slug .= '-' . $slugPrefix;
                }
                $checkSlug = Article::where('type', $this->_type)->where('slug', $slug)->exists();
                $slugPrefix++;
            } while ($checkSlug || ($this->_type == 1 && in_array($slug, $this->_pipopaArticleSlugBlock)));

            $validated['slug'] = $slug;
        }

        // Set type
        $validated['type'] = $this->_type;

        // Set current user as author
        $validated['user_id'] = auth()->id();

        // Calculate reading time
        $validated['view_time'] = Article::calculateReadingTime($validated['content']);

        // Generate preview key
        $validated['preview_key'] = Article::generatePreviewKey();

        // Validate and set primary_category_id
        if (! empty($validated['categories'])) {
            if (empty($validated['primary_category_id']) || ! in_array($validated['primary_category_id'], $validated['categories'])) {
                $validated['primary_category_id'] = $validated['categories'][0];
            }
        } else {
            $validated['primary_category_id'] = null;
        }

        // Check status permissions
        $user = Auth::user();
        if (($this->_type == 0 && in_array($validated['status'], ['publish', 'future']) && ! $user->can('articles.mattock.publish') && ! $user->can('articles.mattock.owner.publish')) ||
            ($this->_type == 1 && in_array($validated['status'], ['publish', 'future']) && ! $user->can('articles.pipopa.publish') && ! $user->can('articles.pipopa.owner.publish'))) {
            $validated['status'] = 'pending';
        }

        // Create article
        $validated['slug'] = urlencode($validated['slug']);
        $article = Article::create($validated);

        // Attach categories
        if (! empty($validated['categories'])) {
            $article->categories()->attach($validated['categories']);
        }

        // Attach tags
        if (! empty($validated['tags'])) {
            $tagIds = [];
            foreach ($validated['tags'] as $tagName) {
                $tag = Tag::where('name', $tagName)
                    ->where('type', $this->_type)
                    ->first();
                if (! $tag) {
                    $tagSlug = Str::slug($this->convertJapaneseToRomaji(trim($tagName)));
                    $tag = Tag::create([
                        'type' => $this->_type,
                        'name' => $tagName,
                        'slug' => $tagSlug,
                    ]);
                }
                $tagIds[] = $tag->id;
            }
            $article->tags()->attach($tagIds);
        }

        // Check if this is a preview action
        if ($request->input('action') === 'preview') {
            return redirect()
                ->route("admin.{$this->_module}.articles.edit", ['article' => $article, 'openPreview' => 'true'])
                ->with('success', 'Article saved as draft. You can now preview it.');
        }

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', 'Article created successfully.');
    }

    /**
     * Display the specified resource.
     */
    public function show(Article $article)
    {
        if ($article->type != $this->_type) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Article not found.');
        }

        $article->load(['user', 'categories', 'tags']);

        return Inertia::render("admin/{$this->_module}/articles/Show", [
            'article' => $article,
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Article $article)
    {
        if ($article->type != $this->_type) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Article not found.');
        }

        $article->load(['categories', 'tags']);
        $article->load(['primaryCategory' => function ($query) {
            $query->with('parent');
        }]);
        $categories = Category::where('type', $this->_type)->get();
        $tags = Tag::where('type', $this->_type)->get();
        $article->slug = urldecode($article->slug);

        return Inertia::render("admin/{$this->_module}/articles/Edit", [
            'article'    => $article,
            'categories' => $categories,
            'tags'       => $tags,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Article $article)
    {
        $validated = $request->validate([
            'title'               => 'required|string|max:255',
            'slug'                => 'nullable|string|max:255',
            'image'               => 'nullable|string|max:500',
            'description'         => 'nullable|string|max:500',
            'content'             => 'nullable|string',
            'status'              => 'required',
            'categories'          => 'nullable|array',
            'categories.*'        => 'exists:categories,id',
            'primary_category_id' => 'nullable|exists:categories,id',
            'tags'                => 'nullable|array',
            'tags.*'              => 'string|max:255',
        ]);

        if ($article->type != $this->_type) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Article not found.');
        }

        // Check permissions
        $user = Auth::user();
        if (($this->_type == 0 && ! $user->can('articles.mattock.edit') && $user->can('articles.mattock.owner.edit')) ||
            ($this->_type == 1 && ! $user->can('articles.pipopa.edit') && $user->can('articles.pipopa.owner.edit'))) {
            if ($article->user_id !== $user->id) {
                return redirect()->route('admin.pages.404');
            }
        }

        $checkArticleTitle = Article::where('type', $this->_type)
            ->where('id', '!=', $article->id)
            ->where('title', $validated['title'])
            ->exists();
        if ($checkArticleTitle) {
            return back()->withErrors(['title' => 'Title already exists.']);
        }

        if (isset($validated['slug']) && $validated['slug'] != '') {
            // Sanitize the slug
            $validated['slug'] = $this->sanitizeSlug($validated['slug']);

            $checkArticleSlug = Article::where('type', $this->_type)
                ->where('id', '!=', $article->id)
                ->where('slug', $validated['slug'])
                ->exists();
            if ($checkArticleSlug || ($this->_type == 1 && in_array($validated['slug'], $this->_pipopaArticleSlugBlock))) {
                return back()->withErrors(['slug' => 'URL already exists.']);
            }
        } else {
            $slugPrefix = 0;
            do {
                $slug = Str::slug($this->convertJapaneseToRomaji(trim($validated['title'])));
                if ($slugPrefix > 0) {
                    $slug .= '-' . $slugPrefix;
                }
                $checkSlug = Article::where('type', $this->_type)
                    ->where('id', '!=', $article->id)
                    ->where('slug', $slug)
                    ->exists();
                $slugPrefix++;
            } while ($checkSlug || ($this->_type == 1 && in_array($slug, $this->_pipopaArticleSlugBlock)));

            $validated['slug'] = $slug;
        }

        // Handle image changes
        if (isset($validated['image'])) {
            if ($validated['image'] === null) {
                // User wants to remove the image
                if ($article->image) {
                    Storage::disk('public')->delete($article->image);
                }
            } elseif ($validated['image'] !== $article->image) {
                // New image provided, delete old image
                if ($article->image) {
                    Storage::disk('public')->delete($article->image);
                }
            }
        }

        // Update reading time if content changed
        if ($request->input('content') !== $article->content) {
            $validated['view_time'] = Article::calculateReadingTime($validated['content']);
        }

        // Validate and set primary_category_id
        if (! empty($validated['categories'])) {
            if (empty($validated['primary_category_id']) || ! in_array($validated['primary_category_id'], $validated['categories'])) {
                $validated['primary_category_id'] = $validated['categories'][0];
            }
        } else {
            $validated['primary_category_id'] = null;
        }

        // Check status permissions
        if (($this->_type == 0 && in_array($validated['status'], ['publish', 'future']) && ! $user->can('articles.mattock.publish') && ! $user->can('articles.mattock.owner.publish')) ||
            ($this->_type == 1 && in_array($validated['status'], ['publish', 'future']) && ! $user->can('articles.pipopa.publish') && ! $user->can('articles.pipopa.owner.publish'))) {
            $validated['status'] = 'pending';
        }

        // Update article
        $validated['slug'] = urlencode($validated['slug']);
        $article->update($validated);

        // Sync categories
        if (isset($validated['categories'])) {
            $article->categories()->sync($validated['categories']);
        } else {
            $article->categories()->detach();
        }

        // Sync tags
        if (isset($validated['tags'])) {
            $tagIds = [];
            foreach ($validated['tags'] as $tagName) {
                $tag = Tag::where('name', $tagName)
                    ->where('type', $this->_type)
                    ->first();
                if (! $tag) {
                    $tagSlug = Str::slug($this->convertJapaneseToRomaji(trim($tagName)));
                    $tag = Tag::create([
                        'type' => $this->_type,
                        'name' => $tagName,
                        'slug' => $tagSlug,
                    ]);
                }
                $tagIds[] = $tag->id;
            }
            $article->tags()->sync($tagIds);
        } else {
            $article->tags()->detach();
        }

        // Check if this is a preview action
        if ($request->input('action') === 'preview') {
            return redirect()
                ->back()
                ->with('success', 'Article saved successfully. Preview is ready.');
        }

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', 'Article updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Article $article)
    {
        if ($article->type != $this->_type) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Article not found.');
        }

        // Check permissions
        $user = Auth::user();
        if (($this->_type == 0 && ! $user->can('articles.mattock.delete') && $user->can('articles.mattock.owner.delete')) ||
            ($this->_type == 1 && ! $user->can('articles.pipopa.delete') && $user->can('articles.pipopa.owner.delete'))) {
            if ($article->user_id !== $user->id) {
                return redirect()->route('admin.pages.404');
            }
        }

        // Delete image if exists
        if ($article->image) {
            Storage::disk('public')->delete($article->image);
        }

        $article->delete();

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', 'Article deleted successfully.');
    }

    /**
     * Restore a soft deleted article.
     */
    public function restore($id)
    {
        $article = Article::withTrashed()
            ->where('type', $this->_type)
            ->findOrFail($id);

        if (! $article) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Category not found.');
        }

        $article->restore();

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', 'Article restored successfully.');
    }

    /**
     * Force delete an article.
     */
    public function forceDelete($id)
    {
        $article = Article::withTrashed()
            ->where('type', $this->_type)
            ->findOrFail($id);

        if (! $article) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Category not found.');
        }

        // Delete image if exists
        if ($article->image) {
            Storage::disk('public')->delete($article->image);
        }

        $article->forceDelete();

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', 'Article permanently deleted.');
    }

    /**
     * Duplicate an article.
     */
    public function duplicate(Article $article)
    {
        if ($article->type != $this->_type) {
            return redirect()
                ->route('admin.pages.404')
                ->with('error', 'Article not found.');
        }

        $newArticle = $article->replicate();
        $newArticle->title = $article->title . ' (Copy)';
        $newArticle->slug = Article::generateSlug($newArticle->title);
        $newArticle->status = 'draft';
        $newArticle->views = 0;
        $newArticle->preview_key = Article::generatePreviewKey();
        $newArticle->user_id = auth()->id();
        $newArticle->save();

        // Copy relationships
        $newArticle->categories()->attach($article->categories->pluck('id'));
        $newArticle->tags()->attach($article->tags->pluck('id'));

        return redirect()
            ->route("admin.{$this->_module}.articles.edit", $newArticle)
            ->with('success', 'Article duplicated successfully.');
    }

    /**
     * Bulk actions for articles.
     */
    public function bulkAction(Request $request)
    {
        $validated = $request->validate([
            'action'     => 'required|in:delete,publish,draft,private',
            'articles'   => 'required|array',
            'articles.*' => 'exists:articles,id',
        ]);

        $articles = Article::where('type', $this->_type)->whereIn('id', $validated['articles']);

        switch ($validated['action']) {
            case 'delete':
                $articles->delete();
                $message = 'Selected articles deleted successfully.';
                break;
            case 'publish':
            case 'draft':
            case 'private':
                $articles->update(['status' => $validated['action']]);
                $message = "Selected articles status changed to {$validated['action']}.";
                break;
        }

        return redirect()
            ->route("admin.{$this->_module}.articles.index")
            ->with('success', $message);
    }

    /**
     * Sanitize slug to only allow a-z, 0-9, and hyphens
     *
     * @param string $slug
     * @return string
     */
    private function sanitizeSlug($slug)
    {
        if (empty($slug)) {
            return $slug;
        }

        return preg_replace('/^-+|-+$/', '', // Remove leading/trailing hyphens
            preg_replace('/-+/', '-', // Replace multiple consecutive hyphens with single hyphen
                preg_replace('/[^a-z0-9\s-]/', '', // Remove special characters except spaces and hyphens
                    strtolower(trim($slug))
                )
            )
        );
    }

    /**
     * Convert Japanese text to Romaji.
     *
     * @param string $string
     * @return string
     */
    private function convertJapaneseToRomaji($string, $default = 'tag')
    {
        $romaji = null;
        $default = $default . '-' . uniqid();

        try {
            $kakasiOutput = shell_exec('echo ' . escapeshellarg($string) . ' | kakasi -i utf8 -Ha -Ka -Ja -Ea -ka 2>/dev/null');
            $romaji = trim($kakasiOutput);
        } catch (\Exception $e) {
            logger()->error('Failed to convert Japanese to Romaji: ' . $e->getMessage());
        }

        if (empty($romaji) || $romaji === ' ') {
            $romaji = transliterator_transliterate(
                'Any-Latin; NFKD; [:Nonspacing Mark:] Remove; Lower; NFC',
                $string
            );
        }

        if (empty($romaji)) {
            $romaji = $default;
        }

        if ($romaji === $default) {
            logger()->warning('Failed to convert Japanese to Romaji for string: ' . $string);
        }

        return $romaji;
    }
}
