"""Домашнее задание.

Написать функцию вычисляющую метрику пользователей лифта.

ОПИСАНИЕ СИТУАЦИИ
Допустим у нас есть 10-ти этажное здание, в котором есть один лифт вместимостью 10 человек.
На каждом этаже есть кнопка вызова лифта. Когда человеку нужно попасть с этажа Х на этаж У, он нажимает кнопку вызова
лифта, ждёт когда лифт приедет, заходит в лифт, нажимает на кнопку этажа У, и когда лифт приезжает на нужный
этаж - выходит. В час-пик лифт может долго не приезжать, если это происходит, то человек может пойти пешком по лестнице
на нужный ему этаж.

АБ ЭКСПЕРИМЕНТ
Мы хотим изменить алгоритм работы лифта и с помощью АБ теста оценить как это повлияет на время, затрачиваемое людьми
на перемещение между этажами. В качестве метрики будем использовать некоторую статистику от эмпирической функции
распределения затрачиваемого времени пользователей.

МЕТРИКА ЭКСПЕРИМЕНТА
Затрачиваемое время T определим так:
- если человек дождался лифта, то T = t2 - t1, где t2 - время прибытия на целевой этаж, а t1 - время вызова лифта.
- если человек не дождался лифта и пошёл пешком, то T = 2 * (t2 - t1), где t2 - время когда решил пойти пешком, t1 - 
время вызова лифта.

ОТКУДА ДАННЫЕ
Данные генерируются с помощью эмуляции работы лифта и случайного генерирования пользователей.
Для простоты время разбито на интервалы по 10 секунд.

В каждый интервал времени лифт может совершить одно из 3 действий: спуститься на 1 этаж вниз, подняться на 1 этаж 
вверх, произвести посадку/высадку на текущем этаже.

В каждый интервал времени с некоторой вероятностью генерируются люди, которые обладают следующими свойствами:
- текущий этаж, с которого хочет уехать;
- целевой этаж, куда хочет приехать;
- начальное время, когда начал ждать лифт;
- максимальное время ожидания, если не зайдёт в лифт до этого момента, то пойдёт пешком.

ОПИСАНИЕ ДАННЫХ
У нас есть табличка с логами лифта, в которой есть следующие атрибуты:
- time - время в секундах.
- action - состояние лифта в следующие 10 секунд. OPEN - стоит открытый, UP - едет вверх, DOWN - едет вниз.
- user_out - количество вышедших человек
- user_in - количество вошедших человек
- user_total - количество человек в лифте
- floor - текущий этаж
- calls - список вызовов. Вызов описывается парой значений - время вызова и этаж, на который был вызван лифт.
- orders - список заказов, на какие этажи нажимали пользователи, зашедшие в лифт. Аналогично содержит список пар - 
время заказа и целевой этаж.

ЗАДАНИЕ
Нужно написать функцию, которая принимает на вход таблицу pd.DataFrame с логами лифта и возвращает множество значений
метрик пользователей. Метрика описана выше в разделе МЕТРИКА ЭКСПЕРИМЕНТА.

ПРИМЕР
Рассмотрим кусок данных. Тут пользователь вызвал лифт при t1=10, и доехал на нужный этаж при t2=40, значение
метрики для него будет равно t2 - t1 = 30.

time  | action | user_out | user_in | user_total | floor |    calls    |    orders
--------------------------------------------------------------------------------------
0     | open   | 0        | 0       | 0          | 1     |    []       |    []    
10    | up     | 0        | 0       | 0          | 1     | [(10, 2)]   |    []    
20    | open   | 0        | 1       | 1          | 2     |    []       | [(20, 1)]    
30    | down   | 0        | 0       | 0          | 2     |    []       | [(20, 1)]    
40    | open   | 1        | 0       | 0          | 1     |    []       |    []      

ОЦЕНИВАНИЕ
По данным из вашей функции и по истинным значениям метрики будут построены эмпирические функция распределения.
Далее будет вычислено максимальное отличие между полученными ЭФР (аналогично статистике критерия Колмогорова).
Чем меньше отличие D, тем выше балл.
- D <= 0.1 - 10 баллов
- D <= 0.13 - 9 баллов
- D <= 0.16 - 8 баллов
- D <= 0.19 - 7 баллов
и так далее с шагом 0.03.

БОНУСНЫЕ БАЛЛЫ
Топ-5 участников с лучшими результатами получат бонусные баллы.
1 место - 3 балла
2 место - 2 балла
3-5 места - 1 балл
"""

import pandas as pd
import ast


def calculate_metrics(data: pd.DataFrame):
    """Вычисляет значения метрики пользователей.
    
    data - таблица с логами лифта

    return - список значений метрики
    """
    ts = []
    for i in range(data.shape[0]-1):
        row_prev = data.iloc[i, :]
        row_cur = data.iloc[i+1, :]
        
        prev_calls = ast.literal_eval(row_prev["calls"])
        for el in prev_calls:
            cur_calls = ast.literal_eval(row_cur["calls"])
            if el not in cur_calls:
                
                if el[1] == row_cur["floor"] and row_cur["action"] == "open" and row_cur["user_in"] >= 1:
                    orders = ast.literal_eval(row_cur["orders"])
                    for ordr in orders:
                        if ordr[0] == row_cur["time"]:
                            order = ordr
                            break
                    t_order = row_cur["time"] - el[0]
                    for j in range(i+1, data.shape[0]):
                        cur_new_row = data.iloc[j, :]
                        cur_orders = ast.literal_eval(cur_new_row["orders"])
                        if order not in cur_orders and cur_new_row["action"] == "open" and cur_new_row["user_out"] >= 1:
                            t_lift = cur_new_row["time"] - order[0]
                            break
                    t = t_order + t_lift
                    ts.append(t)
                else:
                    t = 2 * (row_cur["time"] - el[0])
                    ts.append(t)
    return ts
