<?php

namespace App\Console\Commands;

use App\Modules\Catalog\Models\Category;
use Illuminate\Console\Command;

/**
 * Re-parents the flat list of categories the WooCommerce product import
 * created (29 root-level categories, one per unique "Categories" column
 * value in the source CSV) under the site's original 7 top-level
 * categories — the ones the storefront nav bar actually has icons and
 * dedicated slugs for (see layouts/app.blade.php's $navCatIcons map).
 *
 * Why this was needed: the nav bar renders every category with
 * parent_id=null (CategoryService::tree()). The import created each CSV
 * category as its own root row, so the bar ballooned from 7 items to ~36.
 * Nesting them under the original 7 removes them from that root-only
 * query without touching which products belong to which category — a
 * product's category assignment (product_category pivot) is unaffected
 * by changing its category's *parent*.
 *
 * This does NOT fix the fact that ~95% of imported products only ever
 * carried the single "Digestive Care" tag in the source data — that's a
 * product-level re-tagging problem, not a category-tree problem, and is
 * out of scope here on purpose.
 *
 * Usage:
 *   php artisan categories:organize            (applies the changes)
 *   php artisan categories:organize --dry-run   (preview only, no writes)
 *
 * Safe to re-run — matching is by category name, so already-reparented
 * categories are simply found again and re-assigned to the same parent
 * (a no-op in effect).
 */
class OrganizeCategoriesCommand extends Command
{
    protected $signature = 'categories:organize {--dry-run : Preview changes without saving}';

    protected $description = 'Nest the flat imported categories under the site\'s original top-level categories';

    /**
     * child category name (as it exists in the DB today) => target parent slug.
     * Parent slugs match layouts/app.blade.php's $navCatIcons keys exactly.
     */
    private const PLAN = [
        // Medicines & OTC
        'Digestive Care'             => 'medicines-otc',
        'First Aid & Wound Care'     => 'medicines-otc',
        'Respiratory & Allergy Care' => 'medicines-otc',
        'Pain & Fever Relief'        => 'medicines-otc', // currently nested under the throwaway "Health Care" root
        'Sleep & Stress Relief'      => 'medicines-otc',
        'Bone & Joint Health'        => 'medicines-otc',
        'Eye & Ear Care'             => 'medicines-otc',

        // Wellness & Nutrition
        'Vitamins & Minerals'        => 'wellness-nutrition',
        'Protein & Fitness'          => 'wellness-nutrition',
        'Weight Management'          => 'wellness-nutrition',
        'Immunity Boosters'          => 'wellness-nutrition',

        // Personal Care
        'Oral Care'                  => 'personal-care',
        'Bath & Body'                => 'personal-care',
        'Skin Care'                  => 'personal-care',
        'Hair Care'                  => 'personal-care',
        'Foot Care'                  => 'personal-care',
        'Nails & Hand Care'          => 'personal-care',
        'Men Grooming'               => 'personal-care',
        'Makeup Essentials'          => 'personal-care',

        // Baby Care
        'Baby Bath & Hygiene'        => 'baby-care',
        'Baby Nutrition'             => 'baby-care',
        'Mother Care Essentials'     => 'baby-care',

        // Ayurvedic & Herbal
        'Ayurvedic Supplements'      => 'ayurvedic-herbal',

        // Medical Supplies
        'Monitoring Devices'         => 'medical-supplies',
        'Mobility Support'           => 'medical-supplies',
        'Personal Safety Devices'    => 'medical-supplies',
        'Step counter'               => 'medical-supplies',

        // Women's Health
        'Sexual Wellness'            => 'womens-health',
    ];

    /** The 7 canonical top-level categories — created if a fresh DB doesn't have them yet. */
    private const CANONICAL_PARENTS = [
        'medicines-otc'      => 'Medicines & OTC',
        'ayurvedic-herbal'   => 'Ayurvedic & Herbal',
        'medical-supplies'   => 'Medical Supplies',
        'personal-care'      => 'Personal Care',
        'baby-care'          => 'Baby Care',
        'wellness-nutrition' => 'Wellness & Nutrition',
        'womens-health'      => "Women's Health",
    ];

    public function handle(): int
    {
        $dryRun = (bool) $this->option('dry-run');
        if ($dryRun) {
            $this->warn('--dry-run: previewing only, nothing will be saved.');
        }

        $parents = $this->resolveCanonicalParents($dryRun);

        // Load every category once, keyed by normalized name, so we can
        // find each PLAN entry regardless of its current parent/slug —
        // child slugs from the import include a numeric parent-id suffix
        // we can't predict ahead of time, so matching by name is the
        // reliable option here.
        $byName = Category::all()->keyBy(fn (Category $c) => $this->normalize($c->name));

        $moved = 0;
        $missing = [];

        foreach (self::PLAN as $childName => $parentSlug) {
            $category = $byName->get($this->normalize($childName));
            $parent   = $parents[$parentSlug] ?? null;

            if (! $category || ! $parent) {
                $missing[] = $childName;
                continue;
            }

            if ((int) $category->parent_id === (int) $parent->id) {
                continue; // already correctly parented — nothing to do
            }

            $this->line("  {$category->name}  →  {$parent->name}");

            if (! $dryRun) {
                $category->forceFill([
                    'parent_id' => $parent->id,
                    'depth'     => 1,
                    'path'      => (string) $parent->id,
                ])->save();
            }

            $moved++;
        }

        if (! empty($missing)) {
            $this->warn('Not found in the database (skipped — check spelling/whether these were imported at all):');
            foreach ($missing as $name) {
                $this->line("   - {$name}");
            }
        }

        // Clean up: the CSV's one hierarchical entry ("Health Care > Pain &
        // Fever Relief") created a "Health Care" root purely to hold that
        // one child. Now that the child has been moved to Medicines & OTC
        // above, delete "Health Care" if it's been left with nothing in it.
        $healthCare = $byName->get($this->normalize('Health Care'));
        if ($healthCare && $healthCare->children()->count() === 0 && $healthCare->products()->count() === 0) {
            $this->line("  Removing now-empty \"Health Care\" placeholder category");
            if (! $dryRun) {
                $healthCare->delete();
            }
        }

        // Anything still sitting at root that isn't one of the 7 canonical
        // categories and wasn't in PLAN is a gap in this command's mapping
        // (e.g. the CSV categories changed since this was written) — flag
        // it instead of silently leaving nav clutter unexplained.
        $stillFlat = Category::whereNull('parent_id')
            ->whereNotIn('slug', array_keys(self::CANONICAL_PARENTS))
            ->pluck('name');
        if ($stillFlat->isNotEmpty()) {
            $this->warn('Still sitting at root level (not covered by this command\'s plan):');
            foreach ($stillFlat as $name) {
                $this->line("   - {$name}");
            }
        }

        $this->newLine();
        $this->info(($dryRun ? 'Would reparent' : 'Reparented') . " {$moved} categories.");

        return self::SUCCESS;
    }

    /** @return array<string, Category> parent slug => Category */
    private function resolveCanonicalParents(bool $dryRun): array
    {
        $parents = [];
        foreach (self::CANONICAL_PARENTS as $slug => $name) {
            $category = Category::where('slug', $slug)->first();

            if (! $category) {
                if ($dryRun) {
                    $this->warn("Canonical parent \"{$name}\" (slug: {$slug}) doesn't exist yet — would be created.");
                    continue;
                }
                $category = Category::create([
                    'slug'         => $slug,
                    'name'         => ['en' => $name],
                    'depth'        => 0,
                    'is_active'    => true,
                    'show_in_menu' => true,
                ]);
                $this->info("Created missing canonical parent: {$name}");
            }

            $parents[$slug] = $category;
        }

        return $parents;
    }

    private function normalize(string $name): string
    {
        // Lowercase, strip anything that isn't a letter/number — makes
        // "Women's Health" and "Women’s Health" (straight vs curly
        // apostrophe, which the WooCommerce export used inconsistently)
        // compare equal instead of silently matching nothing.
        return preg_replace('/[^a-z0-9]/', '', mb_strtolower($name)) ?? '';
    }
}
