<?php

/**
 * @package         Tassos Code Snippets
 * @version         1.0.1-RC2 Free
 *
 * @author          Tassos Marinos <info@tassos.gr>
 * @link            https://www.tassos.gr
 * @copyright       Copyright © 2026 Tassos Marinos All Rights Reserved
 * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
 */

namespace Tassos\CodeSnippets\Administrator\Location;

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Tassos\CodeSnippets\Administrator\Helper\SnippetsHelper;

/**
 * Location Manager
 * 
 * Responsible for:
 * - Fetching snippets from database (single query)
 * - Filtering by publishing rules
 * - Grouping snippets by location
 * - Instantiating and registering location classes
 */
class LocationManager
{
    /**
     * Namespace for location classes
     */
    private const LOCATION_NAMESPACE = 'Tassos\\CodeSnippets\\Administrator\\Location\\';

    /**
     * Initialize all locations with their snippets
     *
     * @return void
     */
    public static function initialize(): void
    {
        // 1. Get all published snippets from database (cached)
        $snippets = SnippetsHelper::getSnippets();

        if (empty($snippets))
        {
            return;
        }

        // 2. Group snippets by location
        // Note: publishing rules (conditions) are evaluated later, inside each
        // location's inject() loop, so they run in the correct client context.
        $groupedSnippets = self::groupByLocation($snippets);

        // 3. For each location, instantiate class and register
        foreach ($groupedSnippets as $locationKey => $locationSnippets)
        {
            self::registerLocation($locationKey, $locationSnippets);
        }
    }

    /**
     * Group snippets by their location
     *
     * @param array $snippets The snippets to group
     * 
     * @return array Associative array: location_key => [snippets]
     */
    private static function groupByLocation(array $snippets): array
    {
        $grouped = [];

        foreach ($snippets as $snippet)
        {
            $location = '';

            // Shortcode snippets are handled by onContentPrepare in the system plugin.
            if ($snippet->insertion_method === 'shortcode')
            {
                continue;
            }

            // Auto-insert snippets use their configured location
            $location = $snippet->location ?? '';

            if (empty($location))
            {
                continue;
            }

            if (!isset($grouped[$location]))
            {
                $grouped[$location] = [];
            }

            $grouped[$location][] = $snippet;
        }

        return $grouped;
    }

    /**
     * Register a location with its snippets
     *
     * @param string $locationKey The location key (e.g., 'site_header')
     * @param array  $snippets    The snippets for this location
     * 
     * @return void
     */
    private static function registerLocation(string $locationKey, array $snippets): void
    {
        // Convert location key to class name: site_header → SiteHeader
        $className = self::keyToClassName($locationKey);
        $fullClassName = self::LOCATION_NAMESPACE . $className;

        // Check if class exists (autoloader will handle loading)
        if (!class_exists($fullClassName))
        {
            // No location class for this key - snippets won't be injected
            return;
        }

        // Verify it extends AbstractLocation
        if (!is_subclass_of($fullClassName, AbstractLocation::class))
        {
            return;
        }

        // Instantiate and register
        $location = new $fullClassName($snippets);
        $location->register();
    }

    /**
     * Convert a location key to a class name
     * 
     * Examples:
     * - site_header → SiteHeader
     * - admin_footer → AdminFooter
     * - pageload → Pageload
     *
     * @param string $key The location key
     * 
     * @return string
     */
    private static function keyToClassName(string $key): string
    {
        // Split by underscore, capitalize each word, join
        $parts = explode('_', $key);
        $parts = array_map('ucfirst', $parts);
        return implode('', $parts);
    }

    /**
     * Get a location instance by key (useful for manual triggering like shortcodes)
     *
     * @param string $locationKey The location key
     * @param array  $snippets    Optional snippets to use (if not provided, fetches from DB)
     * 
     * @return AbstractLocation|null
     */
    public static function getLocation(string $locationKey, array $snippets = []): ?AbstractLocation
    {
        $className = self::keyToClassName($locationKey);
        $fullClassName = self::LOCATION_NAMESPACE . $className;

        if (!class_exists($fullClassName))
        {
            return null;
        }

        if (!is_subclass_of($fullClassName, AbstractLocation::class))
        {
            return null;
        }

        // If no snippets provided, fetch and group for this location
        if (empty($snippets))
        {
            $allSnippets = SnippetsHelper::getSnippets();
            $groupedSnippets = self::groupByLocation($allSnippets);
            $snippets = $groupedSnippets[$locationKey] ?? [];
        }

        return new $fullClassName($snippets);
    }
}
