import logging
import json

from flask import abort, request, jsonify, make_response, session

from auth.decorators import process_auth
from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermission)
from data import model
from endpoints.decorators import anon_protect, parse_repository_name
from endpoints.v1 import v1_bp
from endpoints.v1.models_pre_oci import pre_oci_model as model
from util.audit import track_and_log
from util.names import TAG_ERROR, TAG_REGEX

logger = logging.getLogger(__name__)


@v1_bp.route('/repositories/<repopath:repository>/tags', methods=['GET'])
@process_auth
@anon_protect
@parse_repository_name()
def get_tags(namespace_name, repo_name):
  permission = ReadRepositoryPermission(namespace_name, repo_name)

  if permission.can() or model.repository_is_public(namespace_name, repo_name):
    repo = model.get_repository(namespace_name, repo_name)
    if repo.kind != 'image':
      msg = 'This repository is for managing %s resources and not container images.' % repo.kind
      abort(405, message=msg, namespace=namespace_name)

    tags = model.list_tags(namespace_name, repo_name)
    tag_map = {tag.name: tag.image.docker_image_id for tag in tags}
    return jsonify(tag_map)

  abort(403)


@v1_bp.route('/repositories/<repopath:repository>/tags/<tag>', methods=['GET'])
@process_auth
@anon_protect
@parse_repository_name()
def get_tag(namespace_name, repo_name, tag):
  permission = ReadRepositoryPermission(namespace_name, repo_name)

  if permission.can() or model.repository_is_public(namespace_name, repo_name):
    repo = model.get_repository(namespace_name, repo_name)
    if repo.kind != 'image':
      msg = 'This repository is for managing %s resources and not container images.' % repo.kind
      abort(405, message=msg, namespace=namespace_name)

    image_id = model.find_image_id_by_tag(namespace_name, repo_name, tag)
    if image_id is None:
      abort(404)

    resp = make_response('"%s"' % image_id)
    resp.headers['Content-Type'] = 'application/json'
    return resp

  abort(403)


@v1_bp.route('/repositories/<repopath:repository>/tags/<tag>', methods=['PUT'])
@process_auth
@anon_protect
@parse_repository_name()
def put_tag(namespace_name, repo_name, tag):
  permission = ModifyRepositoryPermission(namespace_name, repo_name)

  if permission.can():
    if not TAG_REGEX.match(tag):
      abort(400, TAG_ERROR)

    repo = model.get_repository(namespace_name, repo_name)
    if repo.kind != 'image':
      msg = 'This repository is for managing %s resources and not container images.' % repo.kind
      abort(405, message=msg, namespace=namespace_name)

    image_id = json.loads(request.data)
    model.create_or_update_tag(namespace_name, repo_name, image_id, tag)

    # Store the updated tag.
    if 'pushed_tags' not in session:
      session['pushed_tags'] = {}

    session['pushed_tags'][tag] = image_id

    return make_response('Created', 200)

  abort(403)


@v1_bp.route('/repositories/<repopath:repository>/tags/<tag>', methods=['DELETE'])
@process_auth
@anon_protect
@parse_repository_name()
def delete_tag(namespace_name, repo_name, tag):
  permission = ModifyRepositoryPermission(namespace_name, repo_name)

  if permission.can():
    repo = model.get_repository(namespace_name, repo_name)
    if repo.kind != 'image':
      msg = 'This repository is for managing %s resources and not container images.' % repo.kind
      abort(405, message=msg, namespace=namespace_name)

    model.delete_tag(namespace_name, repo_name, tag)
    track_and_log('delete_tag', model.get_repository(namespace_name, repo_name), tag=tag)
    return make_response('Deleted', 200)

  abort(403)