<?php namespace JasonWilliams\Feed\Classes;

use JasonWilliams\Feed\Models\Settings;
use JasonWilliams\Feed\Models\FeedItem;
use October\Rain\Network\Http;

class SocialApis
{
  // Update the database with the latest tweets
  public static function updateTwitter()
  {
    $tweets = self::fetchTwitter();

    if (sizeof($tweets) > 0)
    {
      foreach ($tweets as $tweet)
      {
        // Skip tweets created by IFTTT if they have an image attached (because they came from Instagram)
        if (!isset($tweet['retweet_status']) && strpos($tweet['source'], "IFTTT") && isset($tweet['entities']['media'])) continue;

        // Skip any tweets created by Foursquare
        if (!isset($tweet['retweet_status']) && strpos($tweet['source'], "Foursquare")) continue;

        $extradata = array();

        // Get the timestamp before we go down a layer to retweets
        $timestamp = strtotime($tweet['created_at']);

        // Set extra data if this is a retweet
        if (isset($tweet['retweeted_status']))
        {
          $tweet = $tweet['retweeted_status'];
          $extradata['opuser'] = $tweet['user']['screen_name'];
          $extradata['opname'] = $tweet['user']['name'];
          $extradata['opimg'] = $tweet['user']['profile_image_url_https'];
        }

        // Set extra data if there's an attached image
        if (isset($tweet['entities']['media'])) $extradata['img'] = $tweet['entities']['media'][0]['media_url_https'];

        // Convert any extra data into a JSON object
        $extradata = (sizeof($extradata) > 0) ? json_encode($extradata) : "";

        // Create a new FeedItem
        $feeditem = new FeedItem;
        $feeditem->timestamp = $timestamp;
        $feeditem->channel_id = 2;
        $feeditem->title = $tweet['full_text'];
        $feeditem->link = "https://twitter.com/i/web/status/".$tweet['id_str'];
        $feeditem->extra = $extradata;
        $feeditem->save();

        // Are there links to include?
        if (sizeof($tweet['entities']['urls']) > 0)
        {
          foreach ($tweet['entities']['urls'] as $url)
          {
            $feeditem->links()->create([
              'addr' => $url['url'],
              'display' =>$url['display_url']
            ]);
          }
        }

        // Are there tags to include?
        if (sizeof($tweet['entities']['hashtags']))
        {
          foreach ($tweet['entities']['hashtags'] as $tag)
          {
            $feeditem->tags()->create([
              'tag' => $tag['text']
            ]);
          }
        }
      }

      // Set the latest item ID
      Settings::set('twitter_latest_tweet', $tweets[sizeof($tweets) - 1]['id_str']);
    }
  }

  // Update the database with the latest instagram posts
  public static function updateInstagram()
  {
    $posts = self::fetchInstagram();

    if (sizeof($posts) > 0)
    {
      foreach ($posts as $post)
      {
        // Skip videos and albums
        if ($post['media_type'] != "IMAGE") continue;

        // Create a new FeedItem
        $feeditem = new FeedItem;
        $feeditem->timestamp = strtotime($post['timestamp']);
        $feeditem->channel_id = 3;
        $feeditem->title = (isset($post['caption'])) ? $post['caption'] : "";
        $feeditem->link = $post['permalink'];
        $feeditem->extra = json_encode(['img' => $post['media_url']]);
        $feeditem->save();

        // Are there tags to include?
        if (isset($post['caption']) && strpos($post['caption'], '#'))
        {
  				preg_match_all('%\B#\w*[a-zA-Z]+\w*%', $post['caption'], $hashtags);
          foreach ($hashtags[0] as $tag)
          {
            $feeditem->tags()->create([
              'tag' => substr($tag, 1)
            ]);
          }
  			}
      }

      // Set the latest item ID
      Settings::set('instagram_latest_post', strtotime(end($posts)['timestamp']));
    }
  }

  // Update the database with the latest foursquare posts
  public static function updateFoursquare()
  {
    $posts = self::fetchFoursquare();

    if (sizeof($posts) > 0)
    {
      foreach ($posts as $post)
      {
        $extradata = [
          'lat' => $post['venue']['location']['lat'],
          'lng' => $post['venue']['location']['lng'],
          'address' => []
        ];

        // Build the address
        if (isset($post['venue']['location']['address'])) $extradata['address'][] = $post['venue']['location']['address'];
        if (isset($post['venue']['location']['city'])) $extradata['address'][] = $post['venue']['location']['city'];
        if (isset($post['venue']['location']['country'])) $extradata['address'][] = $post['venue']['location']['country'];
        $extradata['address'] = implode(', ', $extradata['address']);

        // Create a new FeedItem
        $feeditem = new FeedItem;
        $feeditem->timestamp = $post['createdAt'];
        $feeditem->channel_id = 6;
        $feeditem->title = $post['venue']['name'];
        $feeditem->body = (isset($post['shout'])) ? $post['shout'] : "";
        $feeditem->extra = json_encode($extradata);
        $feeditem->save();

        // Are there tags to include?
        if (isset($post['shout']) && strpos($post['shout'], '#'))
        {
  				preg_match_all('%\B#\w*[a-zA-Z]+\w*%', $post['shout'], $hashtags);
          foreach ($hashtags[0] as $tag)
          {
            $feeditem->tags()->create([
              'tag' => substr($tag, 1)
            ]);
          }
  			}
      }

      // Set the latest item ID
      Settings::set('foursquare_latest_post', end($posts)['createdAt']);
    }
  }

  // Fetch and return the latest tweets
  private static function fetchTwitter()
  {
    // Set the API endpoint
    $endpoint = "https://api.twitter.com/1.1/statuses/user_timeline.json";

    // Set request parameteres
    $req_params = array(
      'screen_name' => Settings::get('twitter_username'),
      'count' => 200,
      'since_id' => Settings::get('twitter_latest_tweet'),
      'tweet_mode' => 'extended',
      'exclude_replies' => true,
      'include_rts' => true
    );

    // Set oauth parameters
    self::$authobject = array(
      'oauth_token' => Settings::get('twitter_access_token'),
      'oauth_consumer_key' => Settings::get('twitter_consumer_key'),
      'oauth_nonce' => time(),
      'oauth_signature_method' => 'HMAC-SHA1',
      'oauth_timestamp' => time(),
      'oauth_version' => '1.0'
    );

    // Add parameters to oauth array
    self::$authobject = array_merge(self::$authobject, $req_params);

    // Generate the oauth signautre
    $base_string = self::buildBaseString($endpoint, "GET", self::$authobject);
    $composite_key = rawurlencode(Settings::get('twitter_consumer_secret'))."&".rawurlencode(Settings::get('twitter_access_token_secret'));
    self::$authobject['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_string, $composite_key, true));

    // Create the URL by adding the parameters to the endpoint
    $endpoint = $endpoint."?".http_build_query($req_params);

    $tweets = array_reverse(json_decode(Http::get($endpoint, function($http)
    {
      $http->header(self::buildAuthorizationHeader(self::$authobject));
    }), true));

    return $tweets;
  }

  // Fetch and return the latest instagram posts
  private static function fetchInstagram()
  {
    $endpoint = "https://graph.instagram.com/me/media";

    // Set the fields we want back
    $fields = [
      'id',
      'ig-id',
      'caption',
      'media_type',
      'media_url',
      'permalink',
      'timestamp'
    ];

    // Create the URL by adding the parameters to the endpoint
    $endpoint = $endpoint."?".http_build_query([
      'access_token' => Settings::get('instagram_access_token'),
      'fields' => implode(',', $fields),
      'limit' => 100
    ]);

    $posts = json_decode(Http::get($endpoint), true);
    $posts = array_reverse($posts['data']);

    foreach($posts as $postkey => $post)
    {
      if (strtotime($post['timestamp']) <= Settings::get('instagram_latest_post')) unset($posts[$postkey]);
    }

    return $posts;
  }

  // Fetch and return the latest foursquare checkins
  private static function fetchFoursquare()
  {
    $endpoint = "https://api.foursquare.com/v2/users/self/checkins";

    // Create the URL by adding the parameters to the endpoint
    $endpoint = $endpoint."?".http_build_query([
      'oauth_token' => Settings::get('foursquare_access_token'),
      'v' => date('Ymd'),
      'limit' => 250,
      'sort' => 'oldestfirst',
      'afterTimestamp' => Settings::get('foursquare_latest_post') + 1
    ]);

    $posts = json_decode(Http::get($endpoint), true);
    return $posts['response']['checkins']['items'];
  }

  // Function to build a base string for the twitter API
  private static function buildBaseString($baseURI, $method, $params) {
    $r = array();
    ksort($params);
    foreach ($params as $key => $value) {
      $r[] = $key.'='.rawurlencode($value);
    }
    return $method.'&'.rawurlencode($baseURI).'&'.rawurlencode(implode('&', $r));
  }

  // Function to build the OAuth authorization header for twitter
  private static function buildAuthorizationHeader($oauth) {
		$r = 'Authorization: OAuth ';
		$values = array();
		foreach($oauth as $key=>$value)
			$values[] = $key.'="'.rawurlencode($value).'"';
		$r .= implode(', ', $values);
		return $r;
	}

  private static $authobject;
}