import enum
import pytz
import datetime
from sqlalchemy import Column, Integer, Text, Boolean, Float, DateTime, Enum, ForeignKey, CheckConstraint
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class PortfolioStatus(enum.Enum):
    SCOPING = "scoping"
    ASSESSMENT = "assessment"
    TENDERING = "tendering"
    PROJECT_UNDERWAY = "project underway"
    COMPLETION_ON_TRACK = "completion; status: on track"
    COMPLETION_DELAYED = "completion; status: delayed"
    COMPLETION_AT_RISK = "completion; status: at risk"
    COMPLETED = "completion; status: completed"
    NEEDS_REVIEW = "needs review"


class PortfolioGoal(enum.Enum):
    VALUATION_IMPROVEMENT = "Valuation Improvement"
    INCREASING_EPC = "Increasing EPC"
    REDUCING_CO2_EMISSIONS = "Reducing CO2 emissions"
    ENERGY_SAVINGS = "Energy Savings"
    NONE = "None"


class Portfolio(Base):
    __tablename__ = 'portfolio'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(Text, nullable=False)
    budget = Column(Float)
    status = Column(Enum(PortfolioStatus, values_callable=lambda x: [e.value for e in x]), nullable=False)
    goal = Column(Enum(PortfolioGoal, values_callable=lambda x: [e.value for e in x]), nullable=False)
    cost = Column(Float)
    number_of_properties = Column(Integer)
    co2_equivalent_savings = Column(Float)  # Unit is always tonnes so we don't need to store the unit
    energy_savings = Column(Float)  # Unit is always kWh so we don't need to store the unit
    energy_cost_savings = Column(Float)  # Unit is always £ so we don't need to store the unit for the moment
    property_valuation_increase = Column(Float)  # Unit is always £ so we don't need to store the unit for the moment
    rental_yield_increase = Column(Float)  # Unit is always £ so we don't need to store the unit for the moment
    total_work_hours = Column(Float)
    labour_days = Column(Float)
    created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
    updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))


class PropertyCreationStatus(enum.Enum):
    LOADING = "LOADING"
    READY = "READY"
    ERROR = "ERROR"


class Epc(enum.Enum):
    A = "A"
    B = "B"
    C = "C"
    D = "D"
    E = "E"
    F = "F"
    G = "G"


class PropertyModel(Base):
    __tablename__ = 'property'
    id = Column(Integer, primary_key=True, autoincrement=True)
    portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False)
    creation_status = Column(Enum(PropertyCreationStatus), nullable=False)
    uprn = Column(Integer)
    building_reference_number = Column(Integer)
    status = Column(Enum(PortfolioStatus, values_callable=lambda x: [e.value for e in x]), nullable=False)
    address = Column(Text)
    postcode = Column(Text)
    has_pre_condition_report = Column(Boolean)
    has_recommendations = Column(Boolean)
    created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
    updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
    property_type = Column(Text)
    built_form = Column(Text)
    local_authority = Column(Text)
    constituency = Column(Text)
    number_of_rooms = Column(Integer)
    year_built = Column(Text)
    tenure = Column(Text)
    current_epc_rating = Column(Enum(Epc))
    current_sap_points = Column(Float)


class FeatureRating(enum.Enum):
    VERY_GOOD = 5
    GOOD = 4
    AVERAGE = 3
    POOR = 2
    VERY_POOR = 1
    NA = None


rating_lookup = {
    "Very Good": FeatureRating.VERY_GOOD,
    "Good": FeatureRating.GOOD,
    "Average": FeatureRating.AVERAGE,
    "Poor": FeatureRating.POOR,
    "Very Poor": FeatureRating.VERY_POOR,
    "N/A": FeatureRating.NA
}


def get_feature_rating_from_string(rating_str: str):
    return rating_lookup.get(rating_str, FeatureRating.NA)


class PropertyDetailsEpcModel(Base):
    __tablename__ = 'property_details_epc'
    id = Column(Integer, primary_key=True, autoincrement=True)
    property_id = Column(Integer, ForeignKey('property.id'), nullable=False)
    portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False)
    full_address = Column(Text)
    total_floor_area = Column(Float)
    walls = Column(Text)
    walls_rating = Column(Integer, CheckConstraint('walls_rating>=1 AND walls_rating<=5'))
    roof = Column(Text)
    roof_rating = Column(Integer, CheckConstraint('roof_rating>=1 AND roof_rating<=5'))
    floor = Column(Text)
    floor_rating = Column(Integer, CheckConstraint('floor_rating>=1 AND floor_rating<=5'))
    windows = Column(Text)
    windows_rating = Column(Integer, CheckConstraint('windows_rating>=1 AND windows_rating<=5'))
    heating = Column(Text)
    heating_rating = Column(Integer, CheckConstraint('heating_rating>=1 AND heating_rating<=5'))
    heating_controls = Column(Text)
    heating_controls_rating = Column(
        Integer, CheckConstraint('heating_controls_rating>=1 AND heating_controls_rating<=5')
    )
    hot_water = Column(Text)
    hot_water_rating = Column(Integer, CheckConstraint('hot_water_rating>=1 AND hot_water_rating<=5'))
    lighting = Column(Text)
    lighting_rating = Column(Integer, CheckConstraint('lighting_rating>=1 AND lighting_rating<=5'))
    mainfuel = Column(Text)
    ventilation = Column(Text)
    solar_pv = Column(Text)
    solar_hot_water = Column(Text)
    wind_turbine = Column(Text)
    floor_height = Column(Float)
    number_heated_rooms = Column(Integer)
    heat_loss_corridor = Column(Boolean)
    unheated_corridor_length = Column(Float)
    number_of_open_fireplaces = Column(Integer)
    number_of_extensions = Column(Integer)
    number_of_storeys = Column(Integer)
    mains_gas = Column(Boolean)
    energy_tariff = Column(Text)
    primary_energy_consumption = Column(Float)
    co2_emissions = Column(Float)
    adjusted_energy_consumption = Column(Float)


class PropertyDetailsSpatial(Base):
    __tablename__ = "property_details_spatial"
    id = Column(Integer, primary_key=True, autoincrement=True)
    uprn = Column(Integer, nullable=False)
    x_coordinate = Column(Float)
    y_coordinate = Column(Float)
    latitude = Column(Float)
    longitude = Column(Float)
    conservation_status = Column(Boolean)
    is_listed_building = Column(Boolean)
    is_heritage_building = Column(Boolean)


class PropertyDetailsMeter(Base):
    __tablename__ = 'property_details_meter'
    id = Column(Integer, primary_key=True, autoincrement=True)
    uprn = Column(Integer, nullable=False)
    energy_supplier = Column(Text)
    gas_supplier = Column(Text)
    meter_reading_total = Column(Float)
    meter_reading_electricity = Column(Float)
    meter_reading_gas = Column(Float)


class PropertyTargetsModel(Base):
    __tablename__ = 'property_targets'
    id = Column(Integer, primary_key=True, autoincrement=True)
    property_id = Column(Integer, ForeignKey('property.id'), nullable=False)
    portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False)
    created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
    epc = Column(Enum(Epc))
    heat_demand = Column(Text)
