from datetime import datetime
import json

from .. import db


class Config(db.Model):
    """Configuration table

        Holds the extra configuration parameters
    """
    __tablename__ = "configs"
    _id = db.Column(db.Integer, primary_key=True)
    parameter = db.Column(db.String(100), unique=True)
    val = db.Column(db.String(100), unique=True)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "parameter": self.parameter,
            "val": self.val,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Device_type(db.Model):
    __tablename__ = "device_types"
    _id = db.Column(db.Integer, primary_key=True)
    device_type = db.Column(db.String(64))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "device_type": self.device_type,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Device(db.Model):
    __tablename__ = "devices"
    _id = db.Column(db.Integer, primary_key=True)
    device_type_id = db.Column(db.Integer, db.ForeignKey('device_types._id'))
    device_type = db.relationship(Device_type, primaryjoin=device_type_id == Device_type._id)
    address = db.Column(db.String(256))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "device_type_id": self.device_type_id,
            "device_type": self.device_type.serialize,
            "address": self.address,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Doc(db.Model):
    __tablename__ = "docs"
    _id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(256))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "name": self.name,
            "location": self.location,
            "description": self.description,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Tag(db.Model):
    __tablename__ = "tags"
    _id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    tag = db.Column(db.String(128))
    tag_category = db.Column(db.String(128))
    device_id = db.Column(db.Integer, db.ForeignKey('devices._id'))
    device = db.relationship(Device)
    description = db.Column(db.String(64))
    data_type = db.Column(db.String(64))
    change_threshold = db.Column(db.Float)
    guarantee_sec = db.Column(db.Integer)
    map_function = db.Column(db.String(64))
    units = db.Column(db.String(10))
    min_expected = db.Column(db.Float)
    max_expected = db.Column(db.Float)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "name": self.name,
            "tag": self.tag,
            "tag_category": self.tag_category,
            "device_id": self.device_id,
            "device": self.device.serialize,
            "description": self.description,
            "data_type": self.data_type,
            "change_threshold": self.change_threshold,
            "guarantee_sec": self.guarantee_sec,
            "map_function": self.map_function,
            "units": self.units,
            "min_expected": self.min_expected,
            "max_expected": self.max_expected,
            "created_on": self.created_on,
            "updated_on": self.updated_on
        }


class Tag_val(db.Model):
    __tablename__ = "tag_vals"
    _id = db.Column(db.Integer, primary_key=True)
    tag_id = db.Column(db.Integer, db.ForeignKey('tags._id'))
    tag = db.relationship(Tag)
    value = db.Column(db.Float)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "tag_id": self.tag_id,
            "tag": self.tag.serialize,
            "value": self.value,
            "created_on": self.created_on,
            "updated_on": self.updated_on
        }


class Card(db.Model):
    __tablename__ = "cards"
    _id = db.Column(db.Integer, primary_key=True)
    stroke_type = db.Column(db.String(32))
    stroke_number = db.Column(db.Integer)
    surf_pos = db.Column(db.Text)
    surf_lod = db.Column(db.Text)
    down_pos = db.Column(db.Text)
    down_lod = db.Column(db.Text)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    # def __repr__(self):
    #     return self.serialize

    @property
    def serialize(self):
        json_surf_pos = json.loads(self.surf_pos)
        json_surf_lod = json.loads(self.surf_lod)
        json_down_pos = json.loads(self.down_pos)
        json_down_lod = json.loads(self.down_lod)
        return {
            "_id": self._id,
            "surf_pos": json_surf_pos,
            "surf_lod": json_surf_lod,
            "down_pos": json_down_pos,
            "down_lod": json_down_lod,
            "surface_card": list(zip(json_surf_pos, json_surf_lod)),
            "downhole_card": list(zip(json_down_pos, json_down_lod)),
            "created_on": self.created_on,
            "updated_on": self.updated_on
        }


class GaugeOffVal(db.Model):
    __tablename__ = "gauge_off"
    _id = db.Column(db.Integer, primary_key=True)
    spm_average = db.Column(db.Float)
    downhole_gross_stroke_average = db.Column(db.Float)
    downhole_net_stroke_average = db.Column(db.Float)
    electricity_cost_total = db.Column(db.Float)
    fluid_level_average = db.Column(db.Float)
    full_card_production_total = db.Column(db.Float)
    inflow_rate_average = db.Column(db.Float)
    kWh_used_total = db.Column(db.Float)
    kWh_regen_total = db.Column(db.Float)
    lifting_cost_average = db.Column(db.Float)
    peak_pr_load = db.Column(db.Float)
    min_pr_load = db.Column(db.Float)
    percent_run = db.Column(db.Float)
    polished_rod_hp_average = db.Column(db.Float)
    pump_hp_average = db.Column(db.Float)
    production_total = db.Column(db.Float)
    pump_intake_pressure_average = db.Column(db.Float)
    surface_stroke_length_average = db.Column(db.Float)
    tubing_movement_average = db.Column(db.Float)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "spm_average": self.spm_average,
            "downhole_gross_stroke_average": self.downhole_gross_stroke_average,
            "downhole_net_stroke_average": self.downhole_net_stroke_average,
            "electricity_cost_total": self.electricity_cost_total,
            "fluid_level_average": self.fluid_level_average,
            "full_card_production_total": self.full_card_production_total,
            "inflow_rate_average": self.inflow_rate_average,
            "kWh_used_total": self.kWh_used_total,
            "kWh_regen_total": self.kWh_regen_total,
            "lifting_cost_average": self.lifting_cost_average,
            "peak_pr_load": self.peak_pr_load,
            "min_pr_load": self.min_pr_load,
            "percent_run": self.percent_run,
            "polished_rod_hp_average": self.polished_rod_hp_average,
            "pump_hp_average": self.pump_hp_average,
            "production_total": self.production_total,
            "pump_intake_pressure_average": self.pump_intake_pressure_average,
            "surface_stroke_length_average": self.surface_stroke_length_average,
            "tubing_movement_average": self.tubing_movement_average,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class WellTest(db.Model):
    __tablename__ = "well_tests"
    _id = db.Column(db.Integer, primary_key=True)
    duration_hours = db.Column(db.Float)
    volume_h2o_actual = db.Column(db.Float)
    volume_oil_actual = db.Column(db.Float)
    volume_gas_actual = db.Column(db.Float)
    volume_h2o_projected = db.Column(db.Float)
    volume_oil_projected = db.Column(db.Float)
    volume_gas_projected = db.Column(db.Float)
    api_gravity_oil = db.Column(db.Float)
    spc_gravity_h2o = db.Column(db.Float)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "duration_hours": self.duration_hours,
            "volume_h2o_actual": self.volume_h2o_actual,
            "volume_oil_actual": self.volume_oil_actual,
            "volume_gas_actual": self.volume_gas_actual,
            "volume_h2o_projected": self.volume_h2o_projected,
            "volume_oil_projected": self.volume_oil_projected,
            "volume_gas_projected": self.volume_gas_projected,
            "api_gravity_oil": self.api_gravity_oil,
            "spc_gravity_h2o": self.spc_gravity_h2o,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Note(db.Model):
    __tablename__ = "notes"
    _id = db.Column(db.Integer, primary_key=True)
    note_text = db.Column(db.String(256))
    author = db.Column(db.String(128))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "note_text": self.note_text,
            "author": self.author,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class EventConfig(db.Model):
    __tablename__ = "event_configs"
    _id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    event_type = db.Column(db.String(64))
    tag = db.Column(db.String(128))
    condition = db.Column(db.String(64))
    device_id = db.Column(db.Integer, db.ForeignKey('devices._id'))
    device = db.relationship(Device)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "name": self.name,
            "event_type": self.event_type,
            "tag": self.tag,
            "condition": self.condition,
            "device_id": self.device_id,
            "device": self.device.serialize,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class Event(db.Model):
    __tablename__ = "events"
    _id = db.Column(db.Integer, primary_key=True)
    event_id = db.Column(db.Integer, db.ForeignKey('event_configs._id'))
    event = db.relationship(EventConfig)
    event_type = db.Column(db.String(64))
    event_condition = db.Column(db.String(64))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "event_id": self.event_id,
            "event": self.event.serialize,
            "event_type": self.event_type,
            "event_condition": self.event_condition,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class RunStatus(db.Model):
    __tablename__ = "run_status_log"
    _id = db.Column(db.Integer, primary_key=True)
    run_status = db.Column(db.String(64))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "run_status": self.run_status,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class FluidShot(db.Model):
    __tablename__ = "fluid_shots"
    _id = db.Column(db.Integer, primary_key=True)
    pump_intake_pressure = db.Column(db.Float)
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "pump_intake_pressure": self.pump_intake_pressure,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }


class BackupRestore(db.Model):
    __tablename__ = "backup_restore"
    _id = db.Column(db.Integer, primary_key=True)
    tag = db.Column(db.String(128))
    tag_type = db.Column(db.String(128))
    device_id = db.Column(db.Integer, db.ForeignKey('devices._id'))
    device = db.relationship(Device)
    value = db.Column(db.String(128))
    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    @property
    def serialize(self):
        return {
            "_id": self._id,
            "tag": self.tag,
            "tag_type": self.tag_type,
            "device_id": self.device_id,
            "device": self.device.serialize,
            "value": self.value,
            "created_on": self.created_on,
            "updated_on": self.updated_on,
        }
