<?php

namespace Drupal\nodehive_core\Plugin\WireComponent;

use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\wire\View;
use Drupal\wire\WireComponentBase;
use GuzzleHttp\ClientInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides "TopPages" Wire component.
 *
 * @WireComponent(
 *   id = "matomotoppages",
 *   label = @Translation("Top Pages"),
 * )
 */
class MatomoTopPages extends WireComponentBase {

  /**
   * The HTTP client to fetch the stats.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  protected ClientInterface $httpClient;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected LoggerChannelFactoryInterface $loggerFactory;

  /**
   * Stores the selected month and year.
   *
   * @var string
   */
  public string $monthYear;

  /**
   * The Matomo base URL.
   *
   * @var string
   */
  public string $matomoUrl;

  /**
   * The Matomo site ID.
   *
   * @var string
   */
  public string $siteId;

  /**
   * The Matomo API key.
   *
   * @var string
   */
  public string $apiKey;

  /**
   * Constructs a new TopPages component.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \GuzzleHttp\ClientInterface $http_client
   *   The Guzzle HTTP client.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ClientInterface $http_client, LoggerChannelFactoryInterface $logger_factory) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->httpClient = $http_client;
    $this->loggerFactory = $logger_factory;
    // Initialize monthYear with the current month and year.
    $this->monthYear = date('Y-m');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('http_client'),
      $container->get('logger.factory')
    );
  }

  /**
   * This method is called when the component is first mounted.
   *
   * @param string $matomoUrl
   *   The Matomo base URL.
   * @param string $siteId
   *   The Matomo site ID.
   * @param string $apiKey
   *   The Matomo API key.
   */
  public function mount(string $matomoUrl, string $siteId, string $apiKey): void {
    $this->matomoUrl = $matomoUrl;
    $this->siteId = $siteId;
    $this->apiKey = $apiKey;
  }

  /**
   * Render the Wire component view.
   *
   * @return \Drupal\wire\View|null
   *   The rendered view.
   */
  public function render(): ?View {
    return View::fromTpl('matomotoppages', [
      'items' => $this->getTopPages(),
      'month_options' => $this->getMonthYearOptions(),
    ]);
  }

  /**
   * Fetch top pages from Matomo for the selected month and year.
   *
   * @return array
   *   An array of top pages with their statistics.
   */
  private function getTopPages(): array {
    if (empty($this->monthYear)) {
      return [];
    }

    // Parse the selected month and year.
    [$year, $month] = explode('-', $this->monthYear);
    $period = 'month';
    $start_date = "{$year}-{$month}-01";
    $end_date = date("Y-m-t", strtotime($start_date));

    // Construct the API URL.
    $url = "{$this->matomoUrl}/index.php?module=API&method=Actions.getPageUrls&idSite={$this->siteId}&period={$period}&date={$start_date},{$end_date}&format=JSON&token_auth={$this->apiKey}&flat=1";

    try {
      // Make the API request to Matomo.
      $response = $this->httpClient->get($url);
      $data = json_decode($response->getBody(), TRUE);
      $stats = [];

      // Check if the data for the specific month-year exists.
      if (isset($data[$this->monthYear])) {
        // Iterate over each page's data for the specific month-year.
        foreach ($data[$this->monthYear] as $page) {
          if (isset($page['label'], $page['url'])) {
            $stats[] = [
              'url' => $page['url'],
              'label' => $page['label'],
              'hits' => $page['nb_hits'] ?? 0,
              'visits' => $page['nb_visits'] ?? 0,
              'sum_time_spent' => $this->formatSecondsToWatchTime($page['sum_time_spent']) ?? 0,
              'bounce_rate' => $page['bounce_rate'] ?? '0%',
              'exit_rate' => $page['exit_rate'] ?? '0%',
            ];
          }
        }

        // Sort pages by visits.
        usort($stats, function ($a, $b) {
          return $b['visits'] <=> $a['visits'];
        });
      }

      return $stats;
    }
    catch (\Exception $e) {
      // Handle exception or log error based on your needs.
      $this->loggerFactory->get('toppages')->error($e->getMessage());
      // Return an empty array in case of an error.
      return [];
    }
  }

  /**
   * Get options for month-year selection.
   *
   * @return array
   *   An associative array of month-year options.
   */
  private function getMonthYearOptions(): array {
    $options = [];

    // Get the current date.
    $currentDate = new \DateTime();

    // Loop to get the last 12 months.
    for ($i = 0; $i < 12; $i++) {
      $month = $currentDate->format('m');
      $year = $currentDate->format('Y');

      $options["{$year}-{$month}"] = $this->formatMonthYear($year, $month);

      // Subtract one month.
      $currentDate->modify('-1 month');
    }

    return $options;
  }

  /**
   * Format the month-year string.
   *
   * @param int $year
   *   The year.
   * @param string $month
   *   The month.
   *
   * @return string
   *   The formatted month-year string.
   */
  private function formatMonthYear(int $year, string $month): string {
    $monthNames = [
      '01' => $this->t('January'),
      '02' => $this->t('February'),
      '03' => $this->t('March'),
      '04' => $this->t('April'),
      '05' => $this->t('May'),
      '06' => $this->t('June'),
      '07' => $this->t('July'),
      '08' => $this->t('August'),
      '09' => $this->t('September'),
      '10' => $this->t('October'),
      '11' => $this->t('November'),
      '12' => $this->t('December'),
    ];

    return $monthNames[$month] . ' ' . $year;
  }

  /**
   * Converts seconds into a human-readable format: "X h Y min".
   *
   * @param int $seconds
   *   The number of seconds to convert.
   *
   * @return string
   *   The formatted time string.
   */
  private function formatSecondsToWatchTime($seconds) {
    // Calculate hours and minutes.
    $hours = floor($seconds / 3600);
    $minutes = floor(($seconds % 3600) / 60);

    // Format the result as "Watch time (hours) X h Y min".
    return sprintf('%d h %d min', $hours, $minutes);
  }

}
