from wtforms import SubmitField, StringField, FloatField, HiddenField, validators, Form
from flask_wtf import FlaskForm
from flask import request, render_template, redirect
from main import db, app, ma
from sqlalchemy import Sequence
from sqlalchemy.exc import SQLAlchemyError
from status import st, Status
from datetime import datetime, timedelta
import pytz
import socket
from shared import PA_JOB_MANAGER_HOST, PA_JOB_MANAGER_PORT

################################################################################
# Class describing Job in the database, and via sqlalchemy, connected to the DB as well
################################################################################
class JobExtra(db.Model):
    __tablename__ = "jobextra"
    id = db.Column(db.Integer, db.Sequence('jobextra_id_seq'), primary_key=True )
    job_id = db.Column(db.Integer, db.ForeignKey('job.id') )
    name = db.Column(db.String)
    value = db.Column(db.String)

    def __repr__(self):
        return "<id: {}, job_id: {}, name: {}, value: {}>".format(self.id, self.job_id, self.name, self.value )

class Joblog(db.Model):
    id = db.Column(db.Integer, db.Sequence('joblog_id_seq'), primary_key=True )
    job_id = db.Column(db.Integer, db.ForeignKey('job.id'), primary_key=True )
    log_date = db.Column(db.DateTime(timezone=True))
    log = db.Column(db.String)

    def __repr__(self):
        return "<id: {}, job_id: {}, log: {}".format(self.id, self.job_id, self.log )

class Job(db.Model):
    id = db.Column(db.Integer, db.Sequence('job_id_seq'), primary_key=True )
    start_time = db.Column(db.DateTime(timezone=True))
    last_update = db.Column(db.DateTime(timezone=True))
    name = db.Column(db.String)
    state = db.Column(db.String)
    num_files = db.Column(db.Integer)
    current_file_num = db.Column(db.Integer)
    current_file = db.Column(db.String)
    wait_for = db.Column(db.Integer)
    pa_job_state = db.Column(db.String)

    extra = db.relationship( "JobExtra")
    logs = db.relationship( "Joblog")

    def __repr__(self):
        return "<id: {}, start_time: {}, last_update: {}, name: {}, state: {}, num_files: {}, current_file_num: {}, current_file: {}, pa_job_state: {}, wait_for: {}, extra: {}, logs: {}>".format(self.id, self.start_time, self.last_update, self.name, self.state, self.num_files, self.current_file_num, self.current_file, self.pa_job_state, self.wait_for, self.extra, self.logs)


################################################################################
# Utility classes for Jobs
################################################################################
def GetNumActiveJobs():
    ret = db.engine.execute("select count(1)  from job where pa_job_state is distinct from 'Completed'").first()
    return ret.count

def WakePAJobManager():
    try:
        print("Waking up PA Job Manager")
        s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((PA_JOB_MANAGER_HOST, PA_JOB_MANAGER_PORT))
        s.close()
    except Exception as e:
        st.SetAlert("danger")
        st.SetMessage("Failed to connect to job manager, has it crashed?  Exception was:{}".format(e))
    return

###############################################################################
# NewJob takes a name (which will be matched in pa_job_manager.py to run 
# the appropriate job - which will update the Job() until complete
###############################################################################
def NewJob(name, num_files="0", wait_for=None, jex=None ):
    job=Job(start_time='now()', last_update='now()', name=name, state="New", num_files=num_files,
        current_file_num=0, current_file='', 
        wait_for=wait_for, pa_job_state="New" )
    if jex != None:
        for e in jex:
            job.extra.append(e)

    db.session.add(job)
    db.session.commit()

    WakePAJobManager()
    return job

################################################################################
# /jobs -> show current settings
################################################################################
@app.route("/jobs", methods=["GET"])
def jobs():
    page_title='Job list'
    jobs = Job.query.order_by(Job.id.desc()).all() 
    return render_template("jobs.html", jobs=jobs, page_title=page_title)


###############################################################################
# /job/<id> -> GET -> shows status/history of jobs
################################################################################
@app.route("/job/<id>", methods=["GET"])
def joblog(id):
    page_title='Show Job Details'
    joblog = Job.query.get(id)
    logs=Joblog.query.filter(Joblog.job_id==id).order_by(Joblog.log_date).all()
    if joblog.pa_job_state == "Completed":
        duration=(joblog.last_update-joblog.start_time)
    else:
        duration=(datetime.now(pytz.utc)-joblog.start_time)
    duration= duration-timedelta(microseconds=duration.microseconds)
    return render_template("joblog.html", job=joblog, logs=logs, duration=duration, page_title=page_title)

###############################################################################
# /job/<id> -> GET -> shows status/history of jobs
################################################################################
@app.route("/wakeup", methods=["GET"])
def wakeup():
    WakePAJobManager()
    return render_template("base.html")

###############################################################################
# This func creates a new filter in jinja2 to format the time from the db in a
# way that is more readable (converted to local tz too)
################################################################################
@app.template_filter('vicdate')
def _jinja2_filter_datetime(date, fmt=None):
    return date.strftime("%d/%m/%Y %I:%M:%S %p")
