import logging
import re
import random
import os
import time

from google.appengine.ext import ndb
from google.appengine.ext import endpoints
from google.appengine.ext import deferred
from google.appengine.api import memcache
from protorpc import remote

from model import ShortLink
import api_messages
import utils
from api_messages import CreateShortLinkMessageRequest
from api_messages import CreateShortLinkMessageResponse
from api_messages import ListShortLinkMessageRequest
from api_messages import ShortLinkMessage
from api_messages import ListShortLinkMessageResponse
from api_messages import ReadShortLinkMessageRequest
from api_messages import ReadShortLinkMessageResponse
from api_messages import DeleteShortLinkMessageRequest
from api_messages import DeleteShortLinkMessageResponse

NUM_SHARDS = 20
SHARD_KEY_TEMPLATE = 'shard-{}-{:d}'

@endpoints.api(name='shortlink', version='v1', description='Short Link API',
               owner_domain="lnkr.co.za", owner_name="lnkr",
               package_path="android")
class ShortLinkApi(remote.Service):
  """ This is the API for managing short links. """

  def ValidateInput(self, request):
    """ Validate the input for a short link creation request.
    Args:
      request: the request to create a short link.

    Returns:
      A list of validation errors which is empty if there are no errors.
    """

    disallowed_custom = [ 'index.html', 'js', 'style', 'about.html', 'api.html',
                        'stats.html', 'data', 'favicon', 'robots' ];
    validation_errors = []
    if request.short_link:
      if not re.search(r'^[a-zA-Z0-9-.]+$', request.short_link):
        validation_errors.append(('Short links can only be alpha-numeric '
                                  'characters, numbers or . or -'))

      if request.short_link in disallowed_custom:
        validation_errors.append('That short link is already in use.')

      if len(request.short_link) < 3:
        validation_errors.append('Custom short links must be longer than 3 characters')

    if (not request.target_link) or len(request.target_link) == 0:
      validation_errors.append('Please provide a target URL')
    else:
      if not re.search(r'^https?://', request.target_link):
        validation_errors.append('The target URL provided is invalid - only http or https allowed.')

    return validation_errors

  def GenerateShortLinkCode(self, num_links):
    """ Generate a short link code.

    This generates the short link code (i.e. the XyZAbC part in
    http://blah/XyZAbC. The idea came from http://en.wikipedia.org/wiki/Base_36
    Generate more than one at a time in case a link is already taken.

    Args:
      num_links: the number of short links to generate at once.
    Returns:
      A list of short link codes.
    """
    desired_length = 6
    alphabet='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-'

    result = []
    for i in range(num_links):
      base = []
      for i in range(desired_length):
        pos = random.randrange(0, len(alphabet), 1)
        base.append(alphabet[pos])
      result.append(''.join(base))
    return result

  @endpoints.method(CreateShortLinkMessageRequest,
                    CreateShortLinkMessageResponse, name='create',
                    path= '/create', http_method = 'POST')
  def CreateShortLink(self, request):
    """ The API endpoint for creating a short link.

    Args:
      request: the API request to create a short link.
    Returns:
      A message containing either a status code, the short link created and a
      message.

    Creates a short link and stores it in datastore. The flow is
    1) validate the input
    2) for user-chosen short links, check if the short link exists already
    3) generate n short links
    3a) if all n short links are already taken, try again, if still all are
    taken, give up