from app.models import (
    ContactPerson,
    Address,
    Dewar,
    Proposal,
    Shipment,
    Puck,
    Sample,
    DewarType,
    DewarSerialNumber,
    SampleEvent,
)
from datetime import datetime, timedelta
import random
import time
import hashlib


dewar_types = [
    DewarType(id=1, dewar_type="Type A"),
    DewarType(id=2, dewar_type="Type B"),
    DewarType(id=3, dewar_type="Type C"),
]

# Define Dewar serial numbers
serial_numbers = [
    DewarSerialNumber(id=1, serial_number="SN00001", dewar_type_id=1),
    DewarSerialNumber(id=2, serial_number="SN00002", dewar_type_id=1),
    DewarSerialNumber(id=3, serial_number="SN00003", dewar_type_id=2),
    DewarSerialNumber(id=4, serial_number="SN00004", dewar_type_id=2),
    DewarSerialNumber(id=5, serial_number="SN00005", dewar_type_id=3),
    DewarSerialNumber(id=6, serial_number="SN00006", dewar_type_id=3),
]

# Define contact persons
contacts = [
    ContactPerson(
        id=1,
        firstname="Frodo",
        lastname="Baggins",
        phone_number="123-456-7890",
        email="frodo.baggins@lotr.com",
    ),
    ContactPerson(
        id=2,
        firstname="Samwise",
        lastname="Gamgee",
        phone_number="987-654-3210",
        email="samwise.gamgee@lotr.com",
    ),
    ContactPerson(
        id=3,
        firstname="Aragorn",
        lastname="Elessar",
        phone_number="123-333-4444",
        email="aragorn.elessar@lotr.com",
    ),
    ContactPerson(
        id=4,
        firstname="Legolas",
        lastname="Greenleaf",
        phone_number="555-666-7777",
        email="legolas.greenleaf@lotr.com",
    ),
    ContactPerson(
        id=5,
        firstname="Gimli",
        lastname="Son of Gloin",
        phone_number="888-999-0000",
        email="gimli.sonofgloin@lotr.com",
    ),
    ContactPerson(
        id=6,
        firstname="Gandalf",
        lastname="The Grey",
        phone_number="222-333-4444",
        email="gandalf.thegrey@lotr.com",
    ),
    ContactPerson(
        id=7,
        firstname="Boromir",
        lastname="Son of Denethor",
        phone_number="111-222-3333",
        email="boromir.sonofdenethor@lotr.com",
    ),
    ContactPerson(
        id=8,
        firstname="Galadriel",
        lastname="Lady of Lothlórien",
        phone_number="444-555-6666",
        email="galadriel.lothlorien@lotr.com",
    ),
    ContactPerson(
        id=9,
        firstname="Elrond",
        lastname="Half-elven",
        phone_number="777-888-9999",
        email="elrond.halfelven@lotr.com",
    ),
    ContactPerson(
        id=10,
        firstname="Eowyn",
        lastname="Shieldmaiden of Rohan",
        phone_number="000-111-2222",
        email="eowyn.rohan@lotr.com",
    ),
]

# Define return addresses
return_addresses = [
    Address(
        id=1,
        street="123 Hobbiton St",
        city="Shire",
        zipcode="12345",
        country="Middle Earth",
    ),
    Address(
        id=2,
        street="456 Rohan Rd",
        city="Edoras",
        zipcode="67890",
        country="Middle Earth",
    ),
    Address(
        id=3,
        street="789 Greenwood Dr",
        city="Mirkwood",
        zipcode="13579",
        country="Middle Earth",
    ),
    Address(
        id=4,
        street="321 Gondor Ave",
        city="Minas Tirith",
        zipcode="24680",
        country="Middle Earth",
    ),
    Address(
        id=5,
        street="654 Falgorn Pass",
        city="Rivendell",
        zipcode="11223",
        country="Middle Earth",
    ),
]


# Utilize a function to generate unique IDs
def generate_unique_id(length=16):
    base_string = f"{time.time()}{random.randint(0, 10 ** 6)}"
    hash_object = hashlib.sha256(base_string.encode())
    hash_digest = hash_object.hexdigest()
    short_unique_id = "".join(random.choices(hash_digest, k=length))
    return short_unique_id


# Define dewars with unique IDs
dewars = [
    Dewar(
        id=1,
        dewar_name="Dewar One",
        dewar_type_id=1,
        dewar_serial_number_id=2,
        tracking_number="TRACK123",
        return_address_id=1,
        contact_person_id=1,
        status="Ready for Shipping",
        ready_date=datetime.strptime("2023-09-30", "%Y-%m-%d"),
        shipping_date=None,
        arrival_date=None,
        returning_date=None,
        unique_id=generate_unique_id(),
    ),
    Dewar(
        id=2,
        dewar_name="Dewar Two",
        dewar_type_id=3,
        dewar_serial_number_id=1,
        tracking_number="TRACK124",
        return_address_id=2,
        contact_person_id=2,
        status="In Preparation",
        ready_date=None,
        shipping_date=None,
        arrival_date=None,
        returning_date=None,
        unique_id=generate_unique_id(),
    ),
    Dewar(
        id=3,
        dewar_name="Dewar Three",
        dewar_type_id=2,
        dewar_serial_number_id=3,
        tracking_number="TRACK125",
        return_address_id=1,
        contact_person_id=3,
        status="Not Shipped",
        ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
        shipping_date=None,
        arrival_date=None,
        returning_date=None,
        unique_id=None,
    ),
    Dewar(
        id=4,
        dewar_name="Dewar Four",
        dewar_type_id=2,
        dewar_serial_number_id=4,
        tracking_number="",
        return_address_id=1,
        contact_person_id=3,
        status="Delayed",
        ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
        shipping_date=datetime.strptime("2024-01-02", "%Y-%m-%d"),
        arrival_date=None,
        returning_date=None,
        unique_id=None,
    ),
    Dewar(
        id=5,
        dewar_name="Dewar Five",
        dewar_type_id=1,
        dewar_serial_number_id=1,
        tracking_number="",
        return_address_id=1,
        contact_person_id=3,
        status="Returned",
        arrival_date=datetime.strptime("2024-01-03", "%Y-%m-%d"),
        returning_date=datetime.strptime("2024-01-07", "%Y-%m-%d"),
        unique_id=None,
    ),
]

# Define proposals
proposals = [
    Proposal(id=1, number="PROPOSAL-FRODO-001"),
    Proposal(id=2, number="PROPOSAL-GANDALF-002"),
    Proposal(id=3, number="PROPOSAL-ARAGORN-003"),
    Proposal(id=4, number="PROPOSAL-SAURON-004"),
    Proposal(id=5, number="PROPOSAL-MORDOR-005"),
]

# Define shipment specific dewars
specific_dewar_ids1 = [5]
specific_dewar_ids2 = [1, 2]
specific_dewar_ids3 = [3, 4]

specific_dewars1 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids1]
specific_dewars2 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids2]
specific_dewars3 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids3]

# Define shipments
shipments = [
    Shipment(
        id=1,
        shipment_date=datetime.strptime("2024-10-10", "%Y-%m-%d"),
        shipment_name="Shipment from Mordor",
        shipment_status="Delivered",
        contact_person_id=2,
        proposal_id=3,
        return_address_id=1,
        comments="Handle with care",
        dewars=specific_dewars1,
    ),
    Shipment(
        id=2,
        shipment_date=datetime.strptime("2024-10-24", "%Y-%m-%d"),
        shipment_name="Shipment from Mordor",
        shipment_status="In Transit",
        contact_person_id=4,
        proposal_id=4,
        return_address_id=2,
        comments="Contains the one ring",
        dewars=specific_dewars2,
    ),
    Shipment(
        id=3,
        shipment_date=datetime.strptime("2024-10-28", "%Y-%m-%d"),
        shipment_name="Shipment from Mordor",
        shipment_status="In Transit",
        contact_person_id=5,
        proposal_id=5,
        return_address_id=1,
        comments="Contains the one ring",
        dewars=specific_dewars3,
    ),
]

# Define pucks
pucks = [
    Puck(
        id=1,
        puck_name="PUCK001",
        puck_type="Unipuck",
        puck_location_in_dewar=1,
        dewar_id=1,
    ),
    Puck(
        id=2,
        puck_name="PUCK002",
        puck_type="Unipuck",
        puck_location_in_dewar=2,
        dewar_id=1,
    ),
    Puck(
        id=3,
        puck_name="PUCK003",
        puck_type="Unipuck",
        puck_location_in_dewar=3,
        dewar_id=1,
    ),
    Puck(
        id=4,
        puck_name="PUCK004",
        puck_type="Unipuck",
        puck_location_in_dewar=4,
        dewar_id=1,
    ),
    Puck(
        id=5,
        puck_name="PUCK005",
        puck_type="Unipuck",
        puck_location_in_dewar=5,
        dewar_id=1,
    ),
    Puck(
        id=6,
        puck_name="PUCK006",
        puck_type="Unipuck",
        puck_location_in_dewar=6,
        dewar_id=1,
    ),
    Puck(
        id=7,
        puck_name="PUCK007",
        puck_type="Unipuck",
        puck_location_in_dewar=7,
        dewar_id=1,
    ),
    Puck(
        id=8,
        puck_name="PK001",
        puck_type="Unipuck",
        puck_location_in_dewar=1,
        dewar_id=2,
    ),
    Puck(
        id=9,
        puck_name="PK002",
        puck_type="Unipuck",
        puck_location_in_dewar=2,
        dewar_id=2,
    ),
    Puck(
        id=10,
        puck_name="PK003",
        puck_type="Unipuck",
        puck_location_in_dewar=3,
        dewar_id=2,
    ),
    Puck(
        id=11,
        puck_name="PK004",
        puck_type="Unipuck",
        puck_location_in_dewar=4,
        dewar_id=2,
    ),
    Puck(
        id=12,
        puck_name="PK005",
        puck_type="Unipuck",
        puck_location_in_dewar=5,
        dewar_id=2,
    ),
    Puck(
        id=13,
        puck_name="PK006",
        puck_type="Unipuck",
        puck_location_in_dewar=6,
        dewar_id=2,
    ),
    Puck(
        id=14,
        puck_name="P001",
        puck_type="Unipuck",
        puck_location_in_dewar=1,
        dewar_id=3,
    ),
    Puck(
        id=15,
        puck_name="P002",
        puck_type="Unipuck",
        puck_location_in_dewar=2,
        dewar_id=3,
    ),
    Puck(
        id=16,
        puck_name="P003",
        puck_type="Unipuck",
        puck_location_in_dewar=3,
        dewar_id=3,
    ),
    Puck(
        id=17,
        puck_name="P004",
        puck_type="Unipuck",
        puck_location_in_dewar=4,
        dewar_id=3,
    ),
    Puck(
        id=18,
        puck_name="P005",
        puck_type="Unipuck",
        puck_location_in_dewar=5,
        dewar_id=3,
    ),
    Puck(
        id=19,
        puck_name="P006",
        puck_type="Unipuck",
        puck_location_in_dewar=6,
        dewar_id=3,
    ),
    Puck(
        id=20,
        puck_name="P007",
        puck_type="Unipuck",
        puck_location_in_dewar=7,
        dewar_id=3,
    ),
    Puck(
        id=21,
        puck_name="PC002",
        puck_type="Unipuck",
        puck_location_in_dewar=2,
        dewar_id=4,
    ),
    Puck(
        id=22,
        puck_name="PC003",
        puck_type="Unipuck",
        puck_location_in_dewar=3,
        dewar_id=4,
    ),
    Puck(
        id=23,
        puck_name="PC004",
        puck_type="Unipuck",
        puck_location_in_dewar=4,
        dewar_id=4,
    ),
    Puck(
        id=24,
        puck_name="PC005",
        puck_type="Unipuck",
        puck_location_in_dewar=5,
        dewar_id=4,
    ),
    Puck(
        id=25,
        puck_name="PC006",
        puck_type="Unipuck",
        puck_location_in_dewar=6,
        dewar_id=4,
    ),
    Puck(
        id=26,
        puck_name="PC007",
        puck_type="Unipuck",
        puck_location_in_dewar=7,
        dewar_id=4,
    ),
    Puck(
        id=27,
        puck_name="PKK004",
        puck_type="Unipuck",
        puck_location_in_dewar=4,
        dewar_id=5,
    ),
    Puck(
        id=28,
        puck_name="PKK005",
        puck_type="Unipuck",
        puck_location_in_dewar=5,
        dewar_id=5,
    ),
    Puck(
        id=29,
        puck_name="PKK006",
        puck_type="Unipuck",
        puck_location_in_dewar=6,
        dewar_id=5,
    ),
    Puck(
        id=30,
        puck_name="PKK007",
        puck_type="Unipuck",
        puck_location_in_dewar=7,
        dewar_id=5,
    ),
]

# Define samples
samples = []
sample_id_counter = 1

for puck in pucks:
    positions_with_samples = random.randint(1, 16)
    occupied_positions = random.sample(range(1, 17), positions_with_samples)

    for pos in range(1, 17):
        if pos in occupied_positions:
            sample = Sample(
                id=sample_id_counter,
                sample_name=f"Sample{sample_id_counter:03}",
                position=pos,
                puck_id=puck.id,
            )
            samples.append(sample)
            sample_id_counter += 1

# Define possible event types for samples
event_types = ["Mounted", "Failed", "Unmounted", "Lost"]


def generate_sample_events(samples, chance_no_event=0.2, chance_lost=0.1):
    """Generate events for samples with timestamps
    increasing between different samples."""

    events = []
    # Set the start time to yesterday at 9:33 AM
    start_time = datetime.now().replace(
        hour=9, minute=33, second=0, microsecond=0
    ) - timedelta(days=1)

    for sample in samples:
        current_time = start_time

        # Skip some samples with no events
        if random.random() < chance_no_event:
            # Increment start_time for the next sample to reflect time passage
            start_time += timedelta(minutes=10)
            continue

        # Determine initial event type
        event_type = "Failed" if random.random() < 0.05 else "Mounted"

        # Append the initial event
        events.append(
            SampleEvent(
                sample_id=sample.id, event_type=event_type, timestamp=current_time
            )
        )
        current_time += timedelta(
            seconds=50
        )  # Increment the time for subsequent events

        # Proceed if mounted and it's not the last sample
        if event_type == "Mounted" and sample is not samples[-1]:
            # Determine follow-up event
            if random.random() < chance_lost:
                events.append(
                    SampleEvent(
                        sample_id=sample.id, event_type="Lost", timestamp=current_time
                    )
                )
            else:
                events.append(
                    SampleEvent(
                        sample_id=sample.id,
                        event_type="Unmounted",
                        timestamp=current_time,
                    )
                )

        # Increment start_time for the next sample
        start_time += timedelta(minutes=10)

    return events


sample_events = generate_sample_events(samples)
