import logging
import os
from dataclasses import dataclass

import jikoku.config as config
from jikoku.models import *
from jikoku.time import DailyTimePoint
from jikoku.utils import *

Log = logging.getLogger(__name__)


@dataclass
class TrainData:
    train: Train
    busy_until: TimePoint
    free_location: str

    def available(self, at_time: TimePoint) -> bool:
        return self.busy_until.earlier_than(at_time)


def choose_train_heuristic(to_fill: Service, available_trains: list[TrainData]):
    # give precedence to trains at the same location
    trains_at_same_location = [
        t for t in available_trains if t.free_location == to_fill.first_stop.name
    ]
    if trains_at_same_location:
        return trains_at_same_location[0]
    else:
        return available_trains[0]


def schedule(services: list[Service], **kwargs) -> Schedule:
    conf = config.Config()
    for kword, value in kwargs.items():
        if kword in conf.__dict__:
            conf.__dict__[kword] = value
        else:
            Log.error(f"unknown config item {kword}, skipping")

    Log.info(f"using config {config}")

    services.sort(key=lambda s: s.start_time)

    trainsData: list[TrainData] = list()
    trips = list()

    for service in services:
        current_time = service.start_time

        Log.debug(f"Scheduling service {service}")

        Log.debug(f"Current traindata status {service}")

        available_trains = [t for t in trainsData if t.available(current_time)]

        if not available_trains:
            Log.debug("No train available, making a new one")
            using_train = Train(f"train-{generate_unique_name()}")
            data = TrainData(
                using_train,
                (
                    service.end_time
                    + DailyTimePoint(minute=conf.minimum_minutes_between_services)
                ),
                service.last_stop.name,
            )
            trainsData.append(data)
        else:
            data = choose_train_heuristic(service, available_trains)
            using_train = data.train
            data.busy_until = service.end_time + DailyTimePoint(
                minute=conf.minimum_minutes_between_services
            )
            data.free_location = service.last_stop.name

        trips.append(Trip(service, using_train))

    return Schedule("autogenerated schedule", trips)
