<?php

namespace App\Console\Commands;

use App\Models\Menu;
use App\Models\Page;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class MigrateLegacyPages extends Command
{
    protected $signature = 'migrate:legacy-pages
                            {--dry-run : Run without persisting data}
                            {--limit= : Limit records to migrate}';

    protected $description = 'Migrate customer pages from legacy CakePHP database to Laravel application';

    /** @var array<string, int> */
    protected array $stats = [
        'total' => 0,
        'success' => 0,
        'failed' => 0,
        'skipped' => 0,
        'menus_created' => 0,
    ];

    protected string $logFile;

    /** @var array<int|string, int> */
    protected array $menuCache = [];

    /** @var list<array<string, mixed>> */
    protected array $legacyPages = [
        [
            'id' => 6,
            'title' => 'Donations',
            'slug' => 'donations',
            'content' => '<h2>Donations</h2><p>Thank you so much for considering donating to our Rescue!  Any amount you give is incredibly appreciated.</p><p>Electronic Fund Transfers can be made to: tffcares@gmail.com (password if required: kitties)</p>',
            'status' => 'published',
            'menu_id' => 4,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 6,
            'created_at' => '2016-01-23 18:49:16',
            'updated_at' => '2025-12-27 17:27:07',
        ],
        [
            'id' => 7,
            'title' => 'Wish List',
            'slug' => 'wish-list',
            'content' => '<h2>Wish List</h2><p>We are a foster-based rescue that receives absolutely no government funding. Please consider donating the following items, it would be greatly appreciated.</p><p>Donations of both canned and dry cat food are always gratefully accepted!  The specific kinds listed below are very appreciated as they are a great help in special needs cases and for our foster homes, but all food is gladly shared with those in need, including our colony caretakers.</p><p></p><p><strong>Canned Kitten and Cat Food (Needed monthly)</strong></p><ul><li><p>Royal Canin Mother &amp; Babycat Ultra Soft Mousse</p></li><li><p>Royal Canin Kitten Load in Sauce</p></li><li><p>Authority Kitten Pate - Chicken &amp; Liver only</p></li><li><p>Performatrin Ultra or Naturals - Kitten or Adult</p></li><li><p>Fancy Feast - Adult - chicken feast pate or turkey pate only</p></li><li><p>Fancy Feast - Kitten</p></li></ul><p><strong>Dry Kitten and Cat Food (Needed monthly) </strong></p><ul><li><p>Nulo MedalSeries Limited Ingredient Cat Food - Cat &amp; Kitten - Chicken Series</p></li><li><p>Go! Solutions (purple bag - all life stages - chicken/turkey/duck)</p></li><li><p>Performatrin Kitten food</p></li><li><p>Royal Canin Kitten food</p></li><li><p>Wellness brand - all life stages or kitten only</p></li></ul><p><strong>Other</strong></p><ul><li><p>PetAg Kitten Milk Replacer (KMR) Powder 6 oz</p></li><li><p>Goats milk for dogs and cats (frozen liquid) eg Big Country Raw</p></li><li><p>Canned Pumpkin (Pure pumpkin - not pie filling)</p></li></ul><p><strong>Colony Cat Food</strong></p><ul><li><p>Dry Food (any kind)</p></li><li><p>Canned food (any kind)</p></li></ul><p><strong>Litter (Needed monthly) </strong></p><ul><li><p>Clumping litter for adult cats (we mostly use Unscented Fresh 4 Life from Pet Valu, but any brand appreciated)</p></li></ul><p><strong>Miscellaneous:</strong></p><ul><li><p>Miracle Nipples - Original Miracle Nipple Pkg/10 preferred over other nipples available (note original is preferred over mini nipples) Recommended source is <a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://www.squirrelsandmore.com/products/the-miracle-nipple?variant=18974324935.\">https://copperhollow.com/products/miracle-nipple?variant=12493910769775</a>.</p></li><li><p>Advantage II Kitten Flea Treatment</p></li><li><p>Sterile (unopened) syringes - 3 ml, 5 ml, or 12 ml</p></li><li><p>Garbage bags - Kirkland Signature 100 Smart Tie Garbage Bags (66 cm x 85 cm - regular size) from Costco preferred</p></li><li><p>Heavy duty poop scoops (spade style preferred)</p></li><li><p>Scratching posts and cat trees</p></li><li><p>Medium size carriers (big enough to fit 2 cats)</p></li><li><p>Large to XL Dog Crates (36&quot; to 42&quot;)</p></li><li><p>Liquid dish soap - Original Dawn (blue colour with duck on front)</p></li></ul><p></p><h2><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://www.amazon.ca/hz/wishlist/ls/2EIHLCBIULZ7I\"><strong>VISIT OUR AMAZON WISH LIST</strong></a></h2>',
            'status' => 'published',
            'menu_id' => 4,
            'meta_title' => 'yes about us',
            'meta_description' => 'and this is a descr<>',
            'display_order' => 7,
            'created_at' => '2016-03-24 21:00:38',
            'updated_at' => '2025-12-27 17:31:05',
        ],
        [
            'id' => 8,
            'title' => 'Adoption Process and policies',
            'slug' => 'adoption-process-and-policies',
            'content' => '<h2>Adoption Process and Policies</h2><p>Thank you so much for deciding to adopt with The Forgotten Ferals. By choosing to adopt, you are saving a life and helping us to save other cats in the future!</p><p><strong><u>Adoption Process </u></strong></p><p>Please complete our Adoption Application located in our &quot;Apply&quot; section, indicating the cat or kitten you are interested in adopting, and submit. After submitting an application, we will contact you as soon as we can. Please be patient with us; we are an entirely 100% volunteer-run organization and many of us have full-time jobs.</p><p>Our application process includes reference checks, questions (for the adopter and for us), a foster or adoption event visit to meet the cat that you are interested in, and perhaps a home visit.</p><p>Please understand that we only want what is best for the cats &amp; kittens in our care. This process is not meant to be invasive or judgemental, but rather to simply ensure that our cats are getting the best possible chance at a happy forever home, and to give us peace of mind knowing we\'ve made a good match.</p><p><strong>In order to be considered as an adopter, you must:</strong></p><p>Be at least 19 years of age.</p><p>Live in Kingston or the surrounding area. Adoptions to other areas are considered but will depend on the cat.</p><p>Allow a home visit that will include seeing the conditions the animal will be living in and for follow-up medical care as needed.</p><p>Agree, as per adoption contract, that the adoptive cat will be kept indoors and will not be declawed.</p><p>Bring an appropriate pet carrier at the time of adoption, to bring the cat home in.</p>',
            'status' => 'published',
            'menu_id' => 5,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 2,
            'created_at' => '2017-09-27 00:26:32',
            'updated_at' => '2025-12-27 17:32:31',
        ],
        [
            'id' => 9,
            'title' => 'Fostering',
            'slug' => 'fostering',
            'content' => '<h2>Fostering</h2><p>The Forgotten Ferals is ALWAYS in need of good foster homes. These homes provide a loving &amp; safe environment for our kitties to gain the socialization they need prior to adoption. Fostering a cat is one of the most rewarding experiences you can have (other than adopting, of course). By taking a cat temporarily into your home you\'re freeing up a spot so that we can rescue another cat. Fostering saves lives!</p><p></p><p><strong>WHAT WE ARE LOOKING FOR IN A FOSTER:</strong></p><ul><li><p>A safe &amp; clean spare room with a door</p></li><li><p>Time to spend socializing the cat/ kitten, or multiple feedings for the younger kittens</p></li><li><p>If you have animals of your own, that they are spayed/neutered, and vaccinations are up to date.</p></li><li><p>That you live in Kingston or the immediate surrounding area</p></li><li><p>Most importantly…LOVE</p></li></ul><p></p><p><strong>WHAT WE PROVIDE:</strong></p><ul><li><p>The Forgotten Ferals covers the medical cost for the cats/ kitten\'s vaccinations, spay/neuter, deworm, flea treatment (all appointments are booked by TFF)</p></li><li><p>Start-up supplies (Litter box &amp; scoop, litter, food, toys etc.)</p></li><li><p>Advice &amp; guidance</p></li></ul><p>Fostering can be as short as two weeks to more then a few months, depending on the needs of each kitty, and how long it takes to find them their forever home.</p><p>We have a variety of fostering situations as we take in orphaned kittens, feral kittens, pregnant mothers, mothers with kittens and adult cats (female and male). Our busiest time of year is between April and October, but we need foster homes year-round.</p><p>If you would be interested in fostering, please complete a foster application, found in our "Apply" section.</p><p></p><p style=\"text-align: center;\"><strong>Fostering saves lives!</strong></p><p></p>',
            'status' => 'published',
            'menu_id' => 5,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 4,
            'created_at' => '2017-09-27 00:26:54',
            'updated_at' => '2025-12-27 17:34:27',
        ],
        [
            'id' => 11,
            'title' => 'Adoption Fees',
            'slug' => 'adoption-fees',
            'content' => '<h2>Adoption Fees</h2><p><strong><u>Regular Adoption Fees (Effective April 18 2021)</u></strong></p><p>$300.00 all ages</p><p>* We LOVE to see 2 kitties find their forever homes together, especially siblings, so to encourage this, we offer a discount off of the Regular adoption price, on a second kitty, when you adopt two at the same time. The fee to adopt two kitties at the same time is $550.</p><p><strong>All adoption fees must be paid in advance of the cat/kitten being taken to their new home.</strong></p><p>Included in the adoption fee is the spay/neuter, age appropriate vaccinations, deworming &amp; flea treatments. Most have been/will be micro-chipped. All adult cats will come spayed or neutered. We do not spay/neuter kittens until they are 6 months old. If the kitten is not yet ready for spay/neuter, TFF will arrange for the procedure to be done with TFF&#039;s vet, at a later date (the cost of which is included in the adoption fee).</p>',
            'status' => 'published',
            'menu_id' => 5,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 3,
            'created_at' => '2017-09-27 00:28:02',
            'updated_at' => '2025-12-27 17:33:21',
        ],
        [
            'id' => 12,
            'title' => 'Trapping Services & TNVR Program',
            'slug' => 'trapping-services-tnvr-program',
            'content' => '<h2><strong><u>Trapping/ TNVR</u></strong></h2><p>Our Trapping/ TNVR (Trap/Neuter/ Vaccinate/ Return) services are provided on a "case by case" basis. All requests are reviewed by our committee, and the decision on whether we will be able to provide this service is based on many factors including time, location, circumstances, and resources such as available foster homes (if applicable) and funds. We are a 100% volunteer run rescue that relies solely on donations and fundraising.</p><p>Each circumstance is different.</p><p>Some we are able to easily assist with, such as trapping a friendly stray cat and/ or kittens for <strong><u>OTHER</u></strong> organizations, that already have a place for them to go to, once they are trapped. This situation is just a matter of coordinating a volunteer\'s available free time, and possible travel expense.</p><p>Other situations, such as requests to trap strays and/ or ferals that have no place to go once trapped, can be very complicated. It\'s easy enough (sometimes) to trap the cats &amp; kittens, but then the question becomes a matter of "do we have an available foster home to place them in". There is always a shortage of good foster homes and funds required to feed and provide medical care.</p><p>TNVR (Trap/Neuter/Vaccinate/Return) is a service that we provide to "Managed" colonies to the City of Kingston and surrounding areas. By "Managed" we mean that you (the colony caretaker) have dedicated yourself to care for your colony for the duration of its lifetime by providing food/ water &amp; shelter. An on-site visit to view the colony would be permitted prior to final approval into the program.</p><p>The colony caretaker would be responsible to live-trap the cats from their colony and transport them to their spay/neuter appointments. If need be, we would assist in trapping, and try to make other arrangements on an individual colony basis. This would be dependent on available volunteers.</p><p>Please complete an &quot;Assistance Application&quot; if you would like to further discuss how we may be able to assist you.</p>',
            'status' => 'published',
            'menu_id' => 5,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 1,
            'created_at' => '2017-10-01 16:21:18',
            'updated_at' => '2025-12-27 17:31:45',
        ],
        [
            'id' => 13,
            'title' => 'Adoption Events',
            'slug' => 'adoption-events',
            'content' => '<h2><strong><u>UPCOMING EVENTS:</u></strong></h2><p>Please follow our group on Facebook for all upcoming Adoption Event announcements, as well as other special events &amp; regular updates on cats and kittens currently in care.</p><p><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"http://www.facebook.com/groups/124738484882440/\">The Forgotten Ferals by Donna Cowie-Ducharme</a></p>',
            'status' => 'published',
            'menu_id' => 7,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 0,
            'created_at' => '2017-10-03 20:26:29',
            'updated_at' => '2025-12-27 17:26:06',
        ],
        [
            'id' => 14,
            'title' => 'Fundraising Events',
            'slug' => 'fundraising-events',
            'content' => '<h2>Fundraising Events</h2><p>Please follow our group on Facebook for all Event announcements, as well as regular updates on cats and kittens currently in care.</p><p><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://www.facebook.com/groups/124738484882440/\">The Forgotten Ferals by Donna Cowie-Ducharme</a></p>',
            'status' => 'published',
            'menu_id' => 7,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 0,
            'created_at' => '2017-10-03 20:34:58',
            'updated_at' => '2025-12-27 17:26:37',
        ],
        [
            'id' => 15,
            'title' => 'Barn Cat Program',
            'slug' => 'barn-cat-program',
            'content' => '<h2><strong>BARN CAT PROGRAM</strong></h2><p>We are looking for cat lovers/property owners who need "working cats" for their nice warm barns. There are times, when we rescue a feral cat that cannot be returned to its previous location, or a friendly stray that is not suited to life as an indoor cat. In these circumstances we would look to rehome to a barn.</p><p>All cats would be spayed/ neutered, rabies vaccinated, dewormed &amp; flea treated. This program is designed to find homes for cats that would traditionally be deemed un-adoptable through "normal" adoption procedures. Having barn cats is mutually beneficial. They will help keep down the rodent population, help deter other stray cats from moving in, and as these cats are already spayed/neutered, the property owner won\'t have to worry about endless litters of kittens.</p><p>Cats will be transferred out through a no-charge adoption fee to qualifying homes, although donations towards vet costs are always appreciated.</p><p><strong><u>Qualifying homes must provide:</u></strong></p><p>• Fresh food and water every day</p><p>• A secure, dry barn or building for shelter with heat source</p><p>• The commitment and ability to keep the cats confined to a stall, small room, or crate for 3-4 weeks (depends on the cats and the barn) to acclimate them to their new environment before release.</p><p>• The willingness to trap the cats to provide licensed veterinary care in the event of a severe injury or illness.</p><p>• A staff or volunteer may visit the location to ensure it is appropriate for barn cats. In some circumstances pictures of the barn/shop will be requested instead.</p><p>We may not always have cats available immediately but will try to fill your request as soon as possible. We will maintain a waiting list as the number of cats available as candidates for the Barn Cat Program.</p>',
            'status' => 'published',
            'menu_id' => 5,
            'meta_title' => null,
            'meta_description' => null,
            'display_order' => 0,
            'created_at' => '2018-07-31 19:15:07',
            'updated_at' => '2025-12-27 17:25:24',
        ],
    ];

    public function handle(): int
    {
        $this->initializeLog();

        $this->info('Legacy Customer Pages Migration');
        $this->info('================================');
        $this->newLine();

        if ($this->option('dry-run')) {
            $this->warn('DRY RUN MODE - No data will be persisted');
            $this->newLine();
        }

        try {
            $pageRecords = $this->legacyPages;
            $this->stats['total'] = count($pageRecords);

            if ($limit = $this->option('limit')) {
                $pageRecords = array_slice($pageRecords, 0, (int) $limit);
                $this->warn("Limited to {$limit} records");
            }

            $recordCount = count($pageRecords);
            $this->info("Found {$recordCount} page records to migrate");
            $this->newLine();

            $this->migratePages($pageRecords);

            $this->displaySummary();

            return Command::SUCCESS;
        } catch (\Exception $e) {
            $this->error("Fatal error: {$e->getMessage()}");
            $this->log("FATAL ERROR: {$e->getMessage()}");

            return Command::FAILURE;
        }
    }

    /**
     * @param  list<array<string, mixed>>  $pageRecords
     */
    protected function migratePages(array $pageRecords): void
    {
        $progressBar = $this->output->createProgressBar(count($pageRecords));
        $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% - %message%');

        foreach ($pageRecords as $oldRecord) {
            $progressBar->setMessage("Migrating: {$oldRecord['title']}");

            if (! $this->option('dry-run')) {
                if (DB::table('legacy_page_migrations')->where('old_page_id', $oldRecord['id'])->exists()) {
                    $this->stats['skipped']++;
                    $progressBar->advance();

                    continue;
                }
            }

            try {
                if (! $this->option('dry-run')) {
                    DB::transaction(function () use ($oldRecord) {
                        $menuId = $this->findOrCreateMenuById($oldRecord['menu_id']);

                        $page = new Page([
                            'title' => $oldRecord['title'],
                            'slug' => $this->ensureUniqueSlug($oldRecord['slug']),
                            'content' => $this->cleanContent($oldRecord['content']),
                            'status' => $oldRecord['status'],
                            'is_special' => false,
                            'menu_id' => $this->getHardcodedMenuId($oldRecord['id']),
                            'submenu_id' => null,
                            'requires_auth' => false,
                            'meta_title' => $oldRecord['meta_title'],
                            'meta_description' => $oldRecord['meta_description'],
                            'display_order' => $oldRecord['display_order'],
                        ]);
                        $page->save();

                        if ($oldRecord['created_at']) {
                            $page->created_at = $oldRecord['created_at'];
                        }
                        if ($oldRecord['updated_at']) {
                            $page->updated_at = $oldRecord['updated_at'];
                        }
                        $page->save();

                        DB::table('legacy_page_migrations')->insert([
                            'old_page_id' => $oldRecord['id'],
                            'new_page_id' => $page->id,
                            'migrated_at' => now(),
                        ]);
                    });
                }

                $this->stats['success']++;
            } catch (\Exception $e) {
                $this->log("ERROR: {$oldRecord['title']} (ID: {$oldRecord['id']}) - {$e->getMessage()}");
                $this->stats['failed']++;
            }

            $progressBar->advance();
        }

        $progressBar->finish();
        $this->newLine(2);
    }

    protected function findOrCreateMenuById(?int $menuId): ?int
    {
        if (! $menuId) {
            return null;
        }

        if (isset($this->menuCache[$menuId])) {
            return $this->menuCache[$menuId];
        }

        $menu = Menu::find($menuId);

        if ($menu) {
            $this->menuCache[$menuId] = $menu->id;

            return $menu->id;
        }

        return null;
    }

    protected function getHardcodedMenuId(int $legacyPageId): ?int
    {
        // Hardcoded menu mapping as per requirements:
        // - Adoption Events (ID 13) and Fundraising Events (ID 14) go under "Events" menu
        // - Wish List (ID 7) and Donations (ID 6) go under "How You Can Help" menu
        // - All other pages go under "Information" menu

        if ($legacyPageId === 13 || $legacyPageId === 14) {
            // Adoption Events and Fundraising Events -> Events menu
            return $this->findOrCreateMenuByName('Events');
        } elseif ($legacyPageId === 6 || $legacyPageId === 7) {
            // Donations and Wish List -> How You Can Help menu
            return $this->findOrCreateMenuByName('How You Can Help');
        } else {
            // All other pages -> Information menu
            return $this->findOrCreateMenuByName('Information');
        }
    }

    protected function findOrCreateMenuByName(string $menuName): ?int
    {
        if (isset($this->menuCache[$menuName])) {
            return $this->menuCache[$menuName];
        }

        $menu = Menu::where('name', $menuName)->first();

        if ($menu) {
            $this->menuCache[$menuName] = $menu->id;

            return $menu->id;
        }

        // Create the menu if it doesn't exist
        $newMenu = Menu::create([
            'name' => $menuName,
            'slug' => strtolower(str_replace(' ', '-', $menuName)),
            'icon' => null,
            'parent_id' => null,
            'display_order' => Menu::max('display_order') + 1,
            'is_visible' => true,
            'requires_auth' => false,
        ]);

        $this->menuCache[$menuName] = $newMenu->id;
        $this->stats['menus_created']++;

        return $newMenu->id;
    }

    protected function cleanContent(?string $html): ?string
    {
        if (! $html) {
            return null;
        }

        // Keep HTML for pages as they may have formatting
        $content = html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');

        // Normalize line breaks: convert \r\n to \n
        $content = str_replace("\r\n", "\n", $content);
        $content = str_replace("\r", "\n", $content);

        // Remove literal "rnrn" and "rn" strings that appear in legacy CakePHP data
        $content = str_replace('rnrn', '', $content);

        return trim($content) ?: null;
    }

    protected function createMenuItemForPage(Page $page): void
    {
        // Check if a main-level menu item already exists for this page
        $existingMenu = Menu::where('slug', $page->slug)
            ->whereNull('parent_id')
            ->first();

        if ($existingMenu) {
            return;
        }

        // Get the highest display order for main-level menu items
        $maxDisplayOrder = Menu::whereNull('parent_id')->max('display_order') ?? 0;

        Menu::create([
            'name' => $page->title,
            'slug' => $page->slug,
            'icon' => null,
            'parent_id' => null,
            'display_order' => $maxDisplayOrder + 1,
            'is_visible' => $page->status === 'published',
            'requires_auth' => $page->requires_auth,
        ]);

        $this->stats['menus_created']++;
    }

    protected function ensureUniqueSlug(string $slug): string
    {
        $baseSlug = $slug;
        $counter = 1;

        while (Page::where('slug', $slug)->exists()) {
            $slug = $baseSlug.'-'.$counter;
            $counter++;
        }

        return $slug;
    }

    protected function initializeLog(): void
    {
        $timestamp = now()->format('Y-m-d_His');
        $this->logFile = storage_path("logs/page-migration-{$timestamp}.log");
        file_put_contents($this->logFile, 'Page Migration - '.now()."\n\n");
    }

    protected function log(string $message): void
    {
        file_put_contents($this->logFile, $message."\n", FILE_APPEND);
    }

    protected function displaySummary(): void
    {
        $this->info('Migration Summary');
        $this->info('==================');
        $this->info("Total processed: {$this->stats['total']}");
        $this->info("Successfully migrated: {$this->stats['success']}");
        $this->info("Failed: {$this->stats['failed']}");
        $this->info("Skipped (already migrated): {$this->stats['skipped']}");
        $this->info("Menus created: {$this->stats['menus_created']}");
        $this->newLine();
        $this->info("Log file: {$this->logFile}");

        if ($this->option('dry-run')) {
            $this->warn('DRY RUN - no data was persisted.');
        }
    }
}
