import errno
import io
import json
import os
import urllib
from datetime import datetime
from hashlib import md5
from urllib.parse import urlparse, quote as quoteurl

from PIL import Image
from flask import Blueprint, request, render_template, Response, current_app as app
from sqlalchemy import desc

from app.analysis import DamageAnalysis
from web.models.memento import MementoModel


api_bp = Blueprint('api_bp', __name__, url_prefix='/api',
                    template_folder='src/web/pages/api/views',
                    static_folder='static',
                    static_url_path='/static/home')

@api_bp.route('/', methods=['GET'])
def api_index():
    try:
        parsed_uri = urlparse(request.referrer)
        domain = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri)
    except:
        domain = app.config['BASE_URL'] + '/'

    return render_template("api_index.html", domain=domain)

@api_bp.route('/damage/progress/<path:uri>', methods=['GET'])
def api_damage_progress(uri):
    start = request.args.get('start', '0')
    start = int(start)
    hashed_uri = md5(uri.encode('utf-8')).hexdigest()
    quoted_url = quoteurl(uri).replace('/', '_').replace('.', '-')

    lines_to_send = []
    app_log_file = os.path.join(app.config['CACHE_DIR'], quoted_url, 'app.log')
    if os.path.exists(app_log_file):
        with open(app_log_file, 'r') as f:
            for idx, line in enumerate(f.readlines()):
                if idx >= start:
                    lines_to_send.append(line.strip())

    return Response(response=json.dumps(lines_to_send), status=200, mimetype='application/json')

@api_bp.route('/damage/error/<path:uri>', methods=['GET'])
def api_damage_error(uri):
    hashed_uri = md5(uri.encode('utf-8')).hexdigest()
    quoted_url = quoteurl(uri).replace('/', '_').replace('.', '-')

    result_file = os.path.join(app.config['CACHE_DIR'], quoted_url, 'result.json')
    if os.path.exists(result_file):
        try:
            result = json.load(open(result_file))
            return Response(response=json.dumps(result), status=200, mimetype='application/json')
        except Exception as e:
            return Response(response=json.dumps({'error': True, 'message': e}), status=200,
                            mimetype='application/json')

    return Response(response=json.dumps({'error': False}), status=200, mimetype='application/json')

@api_bp.route('/damage/screenshot/<path:uri>', methods=['GET'])
def api_damage_screenshot(uri):
    hashed_uri = md5(uri.encode('utf-8')).hexdigest()
    quoted_url = quoteurl(uri).replace('/', '_').replace('.', '-')

    screenshot_file = os.path.join(app.config['CACHE_DIR'], quoted_url, 'screenshot.png')
    f = Image.open(screenshot_file)
    o = io.BytesIO()
    f.save(o, format="JPEG")
    s = o.getvalue()

    return Response(response=s, status=200, mimetype='image/png')

# @api_bp.route('/api/damage/<path:uri>/<string:fresh>', methods=['GET'])
@api_bp.route('/damage/<path:uri>', methods=['GET'])
def api_damage(uri):
    uri = uri.encode('utf-8')
    fresh = request.args.get('fresh', 'false')
    fresh = True if fresh.lower() == 'true' else False

    hashed_uri = md5(uri).hexdigest()
    quoted_url = quoteurl(uri).replace('/', '_').replace('.', '-')
    output_dir = os.path.join(app.config['CACHE_DIR'], quoted_url)

    try:
        os.makedirs(output_dir)
    except OSError as e:
        if e.errno != errno.EEXIST: raise

    # If fresh == True, do fresh calculation
    if fresh:
        result = api_bp.do_fresh_calculation(uri, hashed_uri, output_dir)
    else:
        # If there are calculation history, use it
        last_calculation = api_bp.check_calculation_archives(hashed_uri)
        if last_calculation:
            result = last_calculation.result
            time = last_calculation.response_time

            result = json.loads(result)
            result['is_archive'] = True
            result['archive_time'] = time.isoformat()
            # result['calculation_time'] = (api_bp.end_time - api_bp.start_time).seconds
        else:
            result = api_bp.do_fresh_calculation(uri, hashed_uri, output_dir)

    return Response(response=json.dumps(result), status=200, mimetype='application/json')

def check_calculation_archives(api_bp, hashed_uri):
    last_calculation = MementoModel.query\
        .filter(MementoModel.hashed_uri == hashed_uri) \
        .order_by(desc(MementoModel.response_time)) \
        .first()

    return last_calculation

def do_fresh_calculation(api_bp, uri, hashed_url, output_dir):
    # Instantiate MementoModel
    model = MementoModel()
    model.uri = uri
    model.hashed_uri = hashed_url
    model.request_time = datetime.now()

    # # Do crawl and damage calculation
    # damage = MementoDamage(str(uri).encode('utf-8'), output_dir)
    # damage.set_follow_redirection()
    # damage.set_output_mode_json()
    # damage.set_show_debug_message()
    # damage.set_dont_clean_cache_on_finish()
    # damage.run()

    # result = damage.get_result()

    # model.response_time = datetime.now()
    # model.result = json.dumps(result)

    # try:
    #     app.db.session.add(model)
    #     app.db.session.commit()
    # except: pass

    return {}
