<?php
/**
 * Simplyin Payment - Shipping Methods Source Model
 */
declare(strict_types=1);

namespace Simplyin\Payment\Model\Config\Source;

use Magento\Framework\Data\OptionSourceInterface;
use Magento\Shipping\Model\Config as ShippingConfig;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;

class ShippingMethods implements OptionSourceInterface
{
    /**
     * @var ShippingConfig
     */
    private $shippingConfig;

    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * @param ShippingConfig $shippingConfig
     * @param ScopeConfigInterface $scopeConfig
     */
    public function __construct(
        ShippingConfig $shippingConfig,
        ScopeConfigInterface $scopeConfig
    ) {
        $this->shippingConfig = $shippingConfig;
        $this->scopeConfig = $scopeConfig;
    }

    /**
     * Get all active shipping methods as options
     *
     * Returns full method codes in carrier_method format with labels
     * formatted as "Carrier Title - Method Title"
     *
     * @return array
     */
    public function toOptionArray(): array
    {
        $options = [
            ['value' => '', 'label' => __('-- None --')]
        ];

        $carriers = $this->shippingConfig->getActiveCarriers();

        foreach ($carriers as $carrierCode => $carrierModel) {
            $carrierTitle = $this->getCarrierTitle($carrierCode);
            
            if (!$carrierTitle) {
                continue;
            }

            $carrierMethods = $this->getCarrierMethods($carrierModel, $carrierCode);
            
            foreach ($carrierMethods as $methodCode => $methodTitle) {
                $fullMethodCode = $carrierCode . '_' . $methodCode;
                $label = $carrierTitle . ' - ' . $methodTitle;
                
                $options[] = [
                    'value' => $fullMethodCode,
                    'label' => $label
                ];
            }
        }

        return $options;
    }

    /**
     * Get carrier title from configuration
     *
     * @param string $carrierCode
     * @return string|null
     */
    private function getCarrierTitle(string $carrierCode): ?string
    {
        return $this->scopeConfig->getValue(
            'carriers/' . $carrierCode . '/title',
            ScopeInterface::SCOPE_STORE
        );
    }

    /**
     * Get available methods for a carrier
     *
     * @param mixed $carrierModel
     * @param string $carrierCode
     * @return array
     */
    private function getCarrierMethods($carrierModel, string $carrierCode): array
    {
        $methods = [];
        
        // Try to get allowed methods from the carrier model
        if (method_exists($carrierModel, 'getAllowedMethods')) {
            $allowedMethods = $carrierModel->getAllowedMethods();
            
            if (is_array($allowedMethods) && !empty($allowedMethods)) {
                $this->mapAllowedMethods($allowedMethods, $methods);
            }
        }
        
        // If no methods found, use carrier code as default method
        // This handles simple carriers like flatrate that have a single method
        if (empty($methods)) {
            $carrierTitle = $this->getCarrierTitle($carrierCode);
            $methods[$carrierCode] = $carrierTitle ?: ucfirst($carrierCode);
        }
        
        return $methods;
    }

    /**
     * Map allowed methods from the carrier model into the methods array
     *
     * @param array $allowedMethods
     * @param array $methods
     * @return void
     */
    private function mapAllowedMethods(array $allowedMethods, array &$methods): void
    {
        foreach ($allowedMethods as $methodCode => $methodTitle) {
            // Ensure method title is a string
            if (is_string($methodTitle) && !empty($methodTitle)) {
                $methods[$methodCode] = $methodTitle;
            } elseif (is_string($methodCode)) {
                // Use method code as title if title is not available
                $methods[$methodCode] = ucfirst(str_replace('_', ' ', $methodCode));
            }
        }
    }
}
