from sqlalchemy import (
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
    JSON,
    DateTime,
    Boolean,
)
from sqlalchemy.orm import relationship
from .database import Base
from datetime import datetime


class Shipment(Base):
    __tablename__ = "shipments"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    shipment_name = Column(String(255), index=True)
    shipment_date = Column(Date)
    shipment_status = Column(String(255))
    comments = Column(String(200), nullable=True)
    contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))
    return_address_id = Column(Integer, ForeignKey("addresses.id"))
    proposal_id = Column(Integer, ForeignKey("proposals.id"), nullable=True)

    contact_person = relationship("ContactPerson", back_populates="shipments")
    return_address = relationship("Address", back_populates="shipments")
    proposal = relationship("Proposal", back_populates="shipments")
    dewars = relationship("Dewar", back_populates="shipment")


class ContactPerson(Base):
    __tablename__ = "contact_persons"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    firstname = Column(String(255))
    lastname = Column(String(255))
    phone_number = Column(String(255))
    email = Column(String(255))
    shipments = relationship("Shipment", back_populates="contact_person")


class Address(Base):
    __tablename__ = "addresses"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    street = Column(String(255))
    city = Column(String(255))
    zipcode = Column(String(255))
    country = Column(String(255))

    shipments = relationship("Shipment", back_populates="return_address")


class DewarType(Base):
    __tablename__ = "dewar_types"
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    dewar_type = Column(String(255), unique=True, index=True)
    serial_numbers = relationship("DewarSerialNumber", back_populates="dewar_type")


class DewarSerialNumber(Base):
    __tablename__ = "dewar_serial_numbers"
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    serial_number = Column(String(255), index=True)
    dewar_type_id = Column(Integer, ForeignKey("dewar_types.id"))
    dewar_type = relationship("DewarType", back_populates="serial_numbers")


class Dewar(Base):
    __tablename__ = "dewars"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    dewar_name = Column(String(255))
    dewar_type_id = Column(Integer, ForeignKey("dewar_types.id"), nullable=True)
    dewar_serial_number_id = Column(
        Integer, ForeignKey("dewar_serial_numbers.id"), nullable=True
    )
    tracking_number = Column(String(255))
    status = Column(String(255))
    ready_date = Column(Date, nullable=True)
    shipping_date = Column(Date, nullable=True)
    arrival_date = Column(Date, nullable=True)
    returning_date = Column(Date, nullable=True)
    unique_id = Column(String(255), unique=True, index=True, nullable=True)
    shipment_id = Column(Integer, ForeignKey("shipments.id"))
    return_address_id = Column(Integer, ForeignKey("addresses.id"))
    contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))

    shipment = relationship("Shipment", back_populates="dewars")
    return_address = relationship("Address")
    contact_person = relationship("ContactPerson")
    pucks = relationship("Puck", back_populates="dewar")

    dewar_type = relationship("DewarType")
    dewar_serial_number = relationship("DewarSerialNumber")
    slot = relationship("Slot", back_populates="dewar")
    events = relationship("LogisticsEvent", back_populates="dewar")
    beamline_location = None

    @property
    def number_of_pucks(self) -> int:
        return len(self.pucks) if self.pucks else 0

    @property
    def number_of_samples(self) -> int:
        if not self.pucks:
            return 0
        return sum(len(puck.samples) for puck in self.pucks)


class Proposal(Base):
    __tablename__ = "proposals"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    number = Column(String(255))
    shipments = relationship("Shipment", back_populates="proposal")


class Puck(Base):
    __tablename__ = "pucks"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    puck_name = Column(String(255), index=True)
    puck_type = Column(String(255))
    puck_location_in_dewar = Column(Integer)

    # Foreign keys and relationships
    dewar_id = Column(Integer, ForeignKey("dewars.id"))
    dewar = relationship("Dewar", back_populates="pucks")
    samples = relationship("Sample", back_populates="puck")
    events = relationship("PuckEvent", back_populates="puck")


class Sample(Base):
    __tablename__ = "samples"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    sample_name = Column(String(255), index=True)
    proteinname = Column(String(255), index=True)
    position = Column(Integer)
    priority = Column(Integer)
    comments = Column(String(255))
    data_collection_parameters = Column(JSON, nullable=True)

    # Foreign keys and relationships
    dewar_id = Column(Integer, ForeignKey("dewars.id"))
    puck_id = Column(Integer, ForeignKey("pucks.id"))
    puck = relationship("Puck", back_populates="samples")
    events = relationship("SampleEvent", back_populates="sample")


class Slot(Base):
    __tablename__ = "slots"

    id = Column(Integer, primary_key=True, index=True)
    qr_code = Column(String(255), unique=True, index=True)
    label = Column(String(255))
    qr_base = Column(String(255), nullable=True)
    occupied = Column(Boolean, default=False)
    needs_refill = Column(Boolean, default=False)
    dewar_unique_id = Column(String(255), ForeignKey("dewars.unique_id"), nullable=True)
    dewar = relationship("Dewar", back_populates="slot")
    events = relationship("LogisticsEvent", back_populates="slot")


class LogisticsEvent(Base):
    __tablename__ = "logistics_events"

    id = Column(Integer, primary_key=True, index=True)
    dewar_id = Column(Integer, ForeignKey("dewars.id"))
    slot_id = Column(Integer, ForeignKey("slots.id"))
    event_type = Column(String(255), index=True)
    timestamp = Column(DateTime, default=datetime.utcnow)
    dewar = relationship("Dewar", back_populates="events")
    slot = relationship("Slot", back_populates="events")


class SampleEvent(Base):
    __tablename__ = "sample_events"

    id = Column(Integer, primary_key=True, index=True)
    sample_id = Column(Integer, ForeignKey("samples.id"))
    event_type = Column(String(255), index=True)
    timestamp = Column(DateTime, default=datetime.utcnow)

    sample = relationship("Sample", back_populates="events")


class PuckEvent(Base):
    __tablename__ = "puck_events"

    id = Column(Integer, primary_key=True, index=True)
    puck_id = Column(Integer, ForeignKey("pucks.id"))
    tell_position = Column(String(255), nullable=True)
    event_type = Column(String(255), index=True)
    timestamp = Column(DateTime, default=datetime.utcnow)

    puck = relationship("Puck", back_populates="events")