<?php

declare(strict_types=1);

namespace OCA\RePod\Core\EpisodeAction;

use OCA\GPodderSync\Core\EpisodeAction\EpisodeActionReader as CoreEpisodeActionReader;
use OCA\GPodderSync\Db\EpisodeAction\EpisodeActionRepository;
use OCA\RePod\Core\PodcastData\PodcastData;
use OCA\RePod\Service\UserService;

class EpisodeActionReader extends CoreEpisodeActionReader
{
	public function __construct(
		private EpisodeActionRepository $episodeActionRepository,
		private UserService $userService
	) {}

	/**
	 * Base: https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php#L119.
	 * Specs : https://github.com/Podcast-Standards-Project/PSP-1-Podcast-RSS-Specification/blob/main/README.md.
	 *
	 * @return EpisodeActionExtraData[]
	 * @throws \Exception               if the XML data could not be parsed
	 */
	public function parseRssXml(string $xmlString, ?int $fetchedAtUnix = null): array {
		$episodes = [];
		$xml = new \SimpleXMLElement($xmlString);
		$channel = $xml->channel;

		// Find episode by url and add data for it
		/** @var \SimpleXMLElement $item */
		foreach ($channel->item as $item) {
			$url = (string) $item->enclosure['url'];
			$type = (string) $item->enclosure['type'];
			$size = (int) $item->enclosure['length'];
			$guid = (string) $item->guid;

			$iTunesItemChildren = $item->children('itunes', true);
			$iTunesChannelChildren = $channel->children('itunes', true);

			// Get episode action
			$action = $this->episodeActionRepository->findByGuid($guid, $this->userService->getUserUID());

			if ($action) {
				$url = $action->getEpisode();
			} else {
				$action = $this->episodeActionRepository->findByEpisodeUrl($url, $this->userService->getUserUID());
			}

			// Get episode name
			$name = (string) $item->title;

			// Get episode link
			$link = PodcastData::stringOrNull($item->link);

			// Get episode image
			$image = PodcastData::stringOrNull($item->image->url);

			if (!$image && $iTunesItemChildren) {
				$imageAttributes = $iTunesItemChildren->image->attributes();
				$image = PodcastData::stringOrNull($imageAttributes ? (string) $imageAttributes->href : '');
			}

			if (!$image) {
				$image = PodcastData::stringOrNull($channel->image->url);
			}

			if (!$image && $iTunesChannelChildren) {
				$imageAttributes = $iTunesChannelChildren->image->attributes();
				$image = PodcastData::stringOrNull($imageAttributes ? (string) $imageAttributes->href : '');
			}

			if (!$image) {
				preg_match('/<itunes:image\s+href="([^"]+)"/', $xmlString, $matches);
				$image = PodcastData::stringOrNull($matches[1]);
			}

			// Get episode description
			$itemContent = $item->children('content', true);
			if ($itemContent) {
				$description = PodcastData::stringOrNull($itemContent->encoded);
			} else {
				$description = PodcastData::stringOrNull($item->description);
			}

			if (!$description && $iTunesItemChildren) {
				$description = PodcastData::stringOrNull($iTunesItemChildren->summary);
			}

			// Remove tags
			$description = strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $description ?? ''));

			// Get episode duration
			if ($iTunesItemChildren) {
				$rawDuration = PodcastData::stringOrNull($iTunesItemChildren->duration);
			} else {
				$rawDuration = PodcastData::stringOrNull($item->duration);
			}

			$splitDuration = array_reverse(explode(':', $rawDuration ?? ''));
			$duration = (int) $splitDuration[0];
			$duration += !empty($splitDuration[1]) ? (int) $splitDuration[1] * 60 : 0;
			$duration += !empty($splitDuration[2]) ? (int) $splitDuration[2] * 60 : 0;

			// Get episode pubDate
			$rawPubDate = PodcastData::stringOrNull($item->pubDate);
			$pubDate = $rawPubDate ? new \DateTime($rawPubDate) : null;

			$episodes[] = new EpisodeActionExtraData(
				$url,
				$name,
				$link,
				$image,
				$description,
				$fetchedAtUnix ?? (new \DateTime())->getTimestamp(),
				$guid,
				$type,
				$size,
				$pubDate,
				$duration,
				$action
			);
		}

		return $episodes;
	}
}