<?php namespace flow\social;
use SimpleXMLElement;
use stdClass;

if ( ! defined( 'WPINC' ) ) die;
/**
 * Flow-Flow.
 *
 * @package   FlowFlow
 * @author    Looks Awesome <email@looks-awesome.com>

 * @link      http://looks-awesome.com
 * @copyright 2014-2016 Looks Awesome
 */
class FFYoutube extends FFHttpRequestFeed implements LAFeedWithComments {
	private $profile = null;
	private $profiles = array();
	private $userlink = null;
	private $apiKeyPart = '';
	private $image;
	private $media;
	private $videoId;
	private $isSearch = false;
	private $isPlaylist = false;
	private $statistics;
	private $pagination = true;
	private $nextPageToken = '';
	private $pageIndex = 0;
	private $order = false;

	public function __construct() {
		parent::__construct( 'youtube' );
	}

	public function deferredInit($feed) {
		$this->apiKeyPart = '&key=' . $feed->google_api_key;

		if (isset($feed->{'timeline-type'})) {
			$content = urlencode($feed->content);
			switch ( $feed->{'timeline-type'} ) {
				case 'user_timeline':
					$contentRaw = trim($feed->content);
					$this->profile = $this->getProfileSmart($contentRaw);
					$this->url = "https://www.googleapis.com/youtube/v3/playlistItems?part=id%2Csnippet&playlistId={$this->profile->uploads}&maxResults=50" . $this->apiKeyPart;
					break;
				case 'channel':
					$this->profile = $this->getProfile4Search($content);
					$this->userlink = $this->getUserlink4Search($content);
					$this->url = "https://www.googleapis.com/youtube/v3/playlistItems?part=id%2Csnippet&playlistId={$this->profile->uploads}&maxResults=50" . $this->apiKeyPart;
					break;
				case 'playlist':
					$this->isSearch = true;
					$this->isPlaylist = true;
					$this->url = "https://www.googleapis.com/youtube/v3/playlistItems?part=id%2Csnippet&playlistId={$content}&maxResults=50" . $this->apiKeyPart;
					$this->order = $feed->{'playlist-order'};
					break;
				case 'search':
					$this->isSearch = true;
					$this->url = "https://www.googleapis.com/youtube/v3/search?part=id%2Csnippet&q={$content}&type=video&order=date&maxResults=50" . $this->apiKeyPart;
					break;
			}
		}
	}

	protected function getUrl() {
		return parent::getUrl() . $this->nextPageToken;
	}

	protected function items($request){
		$items = array();
		$pxml = json_decode($request);
		if ($this->isSuitablePage($pxml)) {
			$videoResults = array();
			$this->statistics = array();
			foreach ($pxml->items as $item) {
				if ((!isset($item->id->videoId) && !isset($item->snippet->resourceId->videoId)) || !isset($item->snippet->thumbnails)) {
					continue;//TODO fix this case
				}
				$videoId = is_object($item->id) ? $item->id->videoId : $item->snippet->resourceId->videoId;
				array_push($videoResults, $videoId);
			}
			$videoIds = join('%2C', $videoResults);
			$url = "https://www.googleapis.com/youtube/v3/videos?part=id%2Cstatistics&id={$videoIds}" . $this->apiKeyPart;
			$data = $this->getFeedData($url);
			if ( sizeof( $data['errors'] ) > 0 ) {
				$this->errors[] = array(
					'type'    => $this->getType(),
					'message' => $this->filterErrorMessage($data['errors']),
					'url' => $url
				);
			}
			else {
				$statistics = json_decode($data['response']);
				foreach ( $statistics->items as $stat ) {
					$this->statistics[$stat->id] = $stat->statistics;
				}
			}
			$items = $pxml->items;
		}
		$this->pageIndex++;
		return $items;
	}

	protected function isSuitableOriginalPost( $post ) {
		if ((!isset($post->id->videoId) && !isset($post->snippet->resourceId->videoId)) || !isset($post->snippet->thumbnails)) {
			return false;//TODO fix this case
		}
        if ($post->snippet->title === 'Private video' || $post->snippet->title === 'Deleted video'){
            return false;
        }
		return parent::isSuitableOriginalPost( $post );
	}

	protected function prepare( $item ) {
		$this->image = null;
		$this->media = null;

		$this->videoId = is_object($item->id) ? $item->id->videoId : $item->snippet->resourceId->videoId;
		if ($this->isSearch) {
			$channelId      = $item->snippet->channelId;
			$this->userlink = $this->getUserlink4Search( $channelId );
			$this->profile  = $this->getProfile4Search( $channelId );
		}
		return parent::prepare( $item );
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return string
	 */
	protected function getId( $item ) {
		return $this->videoId;
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return string
	 */
	protected function getScreenName($item){
		return $this->profile->screenname;
	}

	protected function getNickname($item){
		return $this->profile->handle;
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return string
	 */
	protected function getHeader($item){
		$strip_tags = 'strip_tags';
		return FFFeedUtils::wrapLinks(function_exists('wp_strip_all_tags') ? wp_strip_all_tags((string)$item->snippet->title) : $strip_tags((string)$item->snippet->title));
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return string
	 */
	protected function getContent( $item ) {
		$strip_tags = 'strip_tags';
		return FFFeedUtils::wrapLinks(function_exists('wp_strip_all_tags') ? wp_strip_all_tags( (string) $item->snippet->description ) : $strip_tags( (string) $item->snippet->description ) );
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return bool
	 */
	protected function showImage($item){
		$thumbnail = null;
		$thumbnails = $item->snippet->thumbnails;
		if (property_exists($thumbnails, 'maxres')){
			$thumbnail = $this->isSuitableThumbnail( $thumbnails->maxres);
		}

		if (is_null($this->image) && isset( $thumbnails->standard)) {
			$thumbnail = $this->isSuitableThumbnail( $thumbnails->standard, $thumbnail);
		}

		if (is_null($this->image) && isset( $thumbnails->high)) {
			$thumbnail = $this->isSuitableThumbnail( $thumbnails->high, $thumbnail);
		}

		if (is_null($this->image) && isset( $thumbnails->medium)) {
			$thumbnail = $this->isSuitableThumbnail( $thumbnails->medium, $thumbnail);
		}

		if (is_null($this->image) && isset( $thumbnails->default)) {
			$thumbnail = $this->isSuitableThumbnail( $thumbnails->default, $thumbnail);
		}

		if (is_null($this->image)){
			$this->image = $this->createImage($thumbnail->url, $thumbnail->width, $thumbnail->height);
		}

		$height = FFFeedUtils::getScaleHeight(600, $thumbnail->width, $thumbnail->height);
		$this->media = $this->createMedia("http://www.youtube.com/v/{$this->videoId}?version=3&f=videos&autoplay=0", 600, $height, "application/x-shockwave-flash");

		return true;
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return array
	 */
	protected function getImage( $item ) {
		return $this->image;
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return array
	 */
	protected function getMedia( $item ) {
		return $this->media;
	}

	/**
	 * @param SimpleXMLElement $item
	 * @return string
	 */
	protected function getProfileImage( $item ) {
		return $this->profile->profileImage;
	}

	protected function getSystemDate( $item ) {
		return strtotime($item->snippet->publishedAt);
	}

	protected function getUserlink( $item ) {
		return $this->userlink;
	}

	protected function getPermalink( $item ) {
		return "https://www.youtube.com/watch?v={$this->videoId}";
	}

	protected function getAdditionalInfo( $item ) {
		$additional = parent::getAdditionalInfo( $item );
		if (array_key_exists($this->videoId, $this->statistics)){
			$stat = $this->statistics[$this->videoId];
			$additional['views']      = isset($stat->viewCount) ? (string)$stat->viewCount : '';
			$additional['likes']      = isset($stat->likeCount) ? (string)$stat->likeCount : '';
			$additional['dislikes']   = isset($stat->dislikeCount) ? (string)$stat->dislikeCount : '';
			$additional['comments']   = isset($stat->commentCount) ? (string)$stat->commentCount : '';
		}
		return $additional;
	}

	protected function nextPage( $result ) {
		return $this->pagination;
	}

	private function getProfile4Search($channelId){
		if (!array_key_exists($channelId, $this->profiles)){
			$profileUrl = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&id={$channelId}" . $this->apiKeyPart;
			$profile = $this->getProfile($profileUrl);
			$this->profiles[$channelId] = $profile;
			return $profile;
		}
		return $this->profiles[$channelId];
	}

    /**
     * @param $profileUrl
     *
     * @return stdClass
     * @throws LASocialException
     * @throws LASocialRequestException
     */
    private function getProfile($profileUrl){
        $profile = new stdClass();
        $data = FFFeedUtils::getFeedDataWithThrowException($profileUrl, 60, false, true, $this->feed->use_curl_follow_location, $this->feed->use_ipv4);
        $pxml = json_decode($data['response']);
        if (isset($pxml->items[0])){
            $item = $pxml->items[0];
            $profile->screenname = $item->snippet->title;
            // customUrl is the channel handle returned by the YouTube API (e.g. "@NASA")
            $handle = isset($item->snippet->customUrl) ? $item->snippet->customUrl : '';
            // Strip leading @ if present
            $profile->handle = ltrim($handle, '@');
            $profile->profileImage = $item->snippet->thumbnails->high->url;
            $profile->uploads = $item->contentDetails->relatedPlaylists->uploads;
            return $profile;
        }
        throw new LASocialException('Please use channel feed type, user feed is not supported for this channel');
    }

    /**
     * Smart profile detection - handles @handles, channel IDs, and legacy usernames
     * 
     * @param string $content The user input (handle, channel ID, or username)
     * @return stdClass
     * @throws LASocialException
     * @throws LASocialRequestException
     */
    private function getProfileSmart($content) {
        $content = trim($content);
        
        // Remove @ prefix if present and remember it was a handle
        $isHandle = (strpos($content, '@') === 0);
        if ($isHandle) {
            $content = substr($content, 1);
        }
        
        // Check if it looks like a channel ID (starts with UC and is 24 chars)
        $isChannelId = (strpos($content, 'UC') === 0 && strlen($content) === 24);
        
        $encodedContent = urlencode($content);
        
        // Strategy 1: If it's clearly a handle (had @) or handle format, use forHandle
        if ($isHandle) {
            $this->userlink = "https://www.youtube.com/@{$content}";
            $profileUrl = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&forHandle={$encodedContent}" . $this->apiKeyPart;
            return $this->getProfile($profileUrl);
        }
        
        // Strategy 2: If it looks like a channel ID, use id parameter
        if ($isChannelId) {
            $this->userlink = "https://www.youtube.com/channel/{$content}";
            $profileUrl = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&id={$encodedContent}" . $this->apiKeyPart;
            return $this->getProfile($profileUrl);
        }
        
        // Strategy 3: Try forUsername first (legacy), fall back to forHandle
        $this->userlink = "https://www.youtube.com/user/{$content}";
        $profileUrl = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&forUsername={$encodedContent}" . $this->apiKeyPart;
        
        try {
            return $this->getProfile($profileUrl);
        } catch (LASocialException $e) {
            // forUsername failed, try forHandle as fallback (many channels use handles now)
            $this->userlink = "https://www.youtube.com/@{$content}";
            $profileUrl = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&forHandle={$encodedContent}" . $this->apiKeyPart;
            
            try {
                return $this->getProfile($profileUrl);
            } catch (LASocialException $e2) {
                // Both failed - provide helpful error message
                // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
                throw new LASocialException("Channel not found. Try using: @handle format, channel ID (starts with UC), or the exact username. Error: " . (function_exists('esc_html') ? esc_html($e2->getMessage()) : htmlspecialchars($e2->getMessage(), ENT_QUOTES, 'UTF-8')));
            }
        }
    }

	private function getUserlink4Search($channelId){
		return "https://www.youtube.com/channel/{$channelId}";
	}

	private function isSuitablePage($pxml){
		$needCountPage = ceil($this->getCount() / 50);
		if ($this->isPlaylist && $this->order){
			$totalResult = intval($pxml->pageInfo->totalResults);
			$countPage = ceil($totalResult / 50);
			$additionalPage = fmod($totalResult, 50) > fmod($this->getCount(),50) ? 0 : 1;
			if (fmod($this->getCount(),50) == 0) $additionalPage = 1;
			$needCountPage = $needCountPage + $additionalPage;
			$isSuitablePage = $this->pageIndex >= ($countPage - $needCountPage);
		}
		else {
			$this->pagination = $needCountPage > $this->pageIndex + 1;
			$isSuitablePage = $needCountPage > $this->pageIndex;
		}

		if (isset($pxml->nextPageToken))
			$this->nextPageToken = "&pageToken=" . $pxml->nextPageToken;
		else
			$this->pagination = false;

		return $isSuitablePage && isset($pxml->items);
	}

	private function isSuitableThumbnail($thumbnail, $current_thumbnail = null){
		if ( round( $thumbnail->width / $thumbnail->height, 2) == 1.78) {
			$this->image = $this->createImage($thumbnail->url, $thumbnail->width, $thumbnail->height);
		}
		if (is_null($current_thumbnail)){
			return $thumbnail;
		}
		return $current_thumbnail;
	}

	public function getComments($item) {
		if (is_object($item)){
			return array();
		}

		$objectId = $item;
		$accessToken = $this->feed->google_api_key;
		$url = "https://www.googleapis.com/youtube/v3/commentThreads?videoId={$objectId}&maxResults={$this->getCount()}&part=snippet&key={$accessToken}";
		$request = $this->getFeedData($url);
		$json = json_decode($request['response']);

		if (!is_object($json) || (is_object($json) && sizeof($json->items) == 0)) {
			if (isset($request['errors']) && is_array($request['errors'])){
				if (!empty($request['errors'])){
					foreach ( $request['errors'] as $error ) {
						$error['type'] = 'youtube';
						//TODO $this->filterErrorMessage
						$this->errors[] = $error;
						throw new \Exception();
					}
				}
			}
			else {
				$this->errors[] = array('type'=>'youtube', 'message' => 'Bad request, access token issue. <a href="http://docs.social-streams.com/article/55-400-bad-request" target="_blank">Troubleshooting</a>.', 'url' => $url);
				throw new \Exception();
			}
			return array();
		}
		else {
			if($json->items){
				// return first 5 comments
				$data = array_slice($json->items, 0, 5);
				$result = array();
				foreach ($data as $item){
					$obj = new stdClass();
					$obj->id = $item->snippet->topLevelComment->id;
					$obj->from = array(
						'id' => $item->snippet->topLevelComment->snippet->authorChannelId->value,
						'full_name' => $item->snippet->topLevelComment->snippet->authorDisplayName
					);
					$obj->text = $item->snippet->topLevelComment->snippet->textDisplay;
					$obj->created_time = $item->snippet->topLevelComment->snippet->publishedAt;
					$result[] = $obj;
				}
				return $result;
			}else{
				$this->errors[] = array(
					'type' => 'instagram',
					'message' => 'User not found',
					'url' => $url
				);
				throw new \Exception();
			}
		}
	}
}