import os
import numpy as np
import pandas as pd

from ref_systems import osm_crs, projected_crs


categories = ['healthcare', 'services', 'transport', 'outdoor', 'supplies', 'restaurant', 'culture', 'education', 'physical']


if __name__ == "__main__":
    # ask the user to select the speed model, yes: slope-dependent walking and biking speed is used, no: length / avg_speed (4.8km/h walk or 21.6 km/h bike)
    terrain = input("Include slope-dependent walking and biking speed? Please enter either 'yes' or 'no': ")

    
    # full path to AGILE_2025_data_code folder
    fullpath = os.path.abspath(os.path.join(os.getcwd(), '..'))

    # output path
    path_results = os.path.join(fullpath, 'results', 'analysis')
    
    # create the output directory if it doesn't exist
    if not os.path.exists(path_results):
        os.makedirs(path_results)

    # read accessibility results per mode and per category
    all_data = {'walk': None, 'bike': None, 'walk_PT': None}
    for mode in ['walk', 'bike', 'walk_PT']:
        print('-----', mode, '-----')
        
        # results for 'walking plus public transport' AND no terrain are not needed --> skip
        if mode == 'walk_PT' and terrain == 'no':
            continue
        
        # input path (mode dependent)
        path_access = os.path.join(fullpath, 'results', 'accessibility', mode, 'terrain_' + terrain)
        
        for category in categories:
            print(category)
            
            # read accessibility results
            data = pd.read_csv(os.path.join(path_access, category + '.csv'))
            data.replace([np.inf, -np.inf], np.nan, inplace=True)

            # add to combined results
            if all_data[mode] is None:
                all_data[mode] = data
                all_data[mode].rename(columns={'time': category}, inplace=True)
            else:
                all_data[mode][category] = data.time

    # hexagon-level accessibility (mean and median) and city-level accessibility for each mode
    index = [f"{idx} [min]" for idx in categories] + ["city-level accessibility [min]", "area of 15-minute city [%]"]
    table_mean = pd.DataFrame(index=index, columns=['walk', 'bike', 'walk_PT'])
    table_median = pd.DataFrame(index=index, columns=['walk', 'bike', 'walk_PT'])
    
    # hexagons that correspond to 15-minute city
    table_mean_15 = pd.DataFrame(index=index[:-1], columns=['walk', 'bike', 'walk_PT'])
    table_median_15 = pd.DataFrame(index=index[:-1], columns=['walk', 'bike', 'walk_PT'])
    for mode in ['walk', 'bike', 'walk_PT']:
        # results for 'walking plus public transport' AND no terrain are not needed --> skip
        if mode == 'walk_PT' and terrain == 'no':
            table_mean.drop(columns=[mode], inplace=True)
            table_median.drop(columns=[mode], inplace=True)
            continue

        # city-level accessibility per hexagon
        all_data[mode]['avg'] = all_data[mode][categories].mean(axis=1, skipna=True)
        
        # hexagon-level accessibility per POI category and average city-level accessibility (average and median)
        mean_hex_level = all_data[mode][categories].mean()
        mean_accessibility_vienna = all_data[mode]['avg'].mean()
        median_hex_level = all_data[mode][categories].median()
        median_accessibility_vienna = all_data[mode]['avg'].median()

        # area of 15-minute city (hexagons with city-level accessibility below 15 min)
        hex_15min = all_data[mode][all_data[mode]['avg'] <= 15]
        area_15min = (len(hex_15min) / len(all_data[mode]) ) * 100

        # average and median accessibility for 15-min hexagons
        mean_accessibility_hex_level_15 = hex_15min[categories].mean()
        mean_accessibility_vienna_15 = hex_15min['avg'].mean()
        median_accessibility_hex_level_15 = hex_15min[categories].median()
        median_accessibility_vienna_15 = hex_15min['avg'].median()

        # prepare the four output dataframes
        new_row1 = pd.DataFrame([[mean_accessibility_vienna]])
        new_row2 = pd.DataFrame([[area_15min]])
        temp = pd.concat([mean_hex_level.copy(), new_row1, new_row2]).reset_index(drop=True)
        temp.columns = [mode]
        table_mean.loc[:, mode] = temp[mode].values

        new_row1 = pd.DataFrame([[median_accessibility_vienna]])
        new_row2 = pd.DataFrame([[area_15min]])
        temp = pd.concat([median_hex_level.copy(), new_row1, new_row2]).reset_index(drop=True)
        temp.columns = [mode]
        table_median.loc[:, mode] = temp[mode].values

        new_row1 = pd.DataFrame([[mean_accessibility_vienna_15]])
        temp = pd.concat([mean_accessibility_hex_level_15.copy(), new_row1]).reset_index(drop=True)
        temp.columns = [mode]
        table_mean_15.loc[:, mode] = temp[mode].values
        
        new_row1 = pd.DataFrame([[median_accessibility_vienna_15]])
        temp = pd.concat([median_accessibility_hex_level_15.copy(), new_row1]).reset_index(drop=True)
        temp.columns = [mode]
        table_median_15.loc[:, mode] = temp[mode].values

    # store results
    table_mean = table_mean.apply(pd.to_numeric)
    table_median = table_median.apply(pd.to_numeric)
    table_mean.round(2).to_csv(os.path.join(path_results, f'average_accessibility_terrain_{terrain}.csv'))
    table_median.round(2).to_csv(os.path.join(path_results, f'median_accessibility_terrain_{terrain}.csv'))

    if terrain == 'no':
        pass
    else:
        table_mean_15 = table_mean_15.apply(pd.to_numeric)
        table_median_15 = table_median_15.apply(pd.to_numeric)
        table_mean_15.round(2).to_csv(os.path.join(path_results, f'15min_average_accessibility_terrain_{terrain}.csv'))
        table_median_15.round(2).to_csv(os.path.join(path_results, f'15min_median_accessibility_terrain_{terrain}.csv'))

    # compute decrease compared to 'walk'
    if terrain == 'no':
        pass
    else:
        table_mean = table_mean.copy().iloc[:-2]
        table_mean_decrease = table_mean[['bike', 'walk_PT']].copy()
        table_mean_decrease['bike'] = ((table_mean['bike'] - table_mean['walk']) / table_mean['walk'] ) * 100
        table_mean_decrease['walk_PT'] = ((table_mean['walk_PT'] - table_mean['walk']) / table_mean['walk'] ) * 100

        table_median = table_median.copy().iloc[:-2]
        table_median_decrease = table_median[['bike', 'walk_PT']].copy()
        table_median_decrease['bike'] = ((table_median['bike'] - table_median['walk']) / table_median['walk']) * 100
        table_median_decrease['walk_PT'] = ((table_median['walk_PT'] - table_median['walk']) / table_median['walk']) * 100

        table_mean_15 = table_mean_15.copy().iloc[:-1]
        table_mean_15_decrease = table_mean_15[['bike', 'walk_PT']].copy()
        table_mean_15_decrease['bike'] = ((table_mean_15['bike'] - table_mean_15['walk']) / table_mean_15['walk'] ) * 100
        table_mean_15_decrease['walk_PT'] = ((table_mean_15['walk_PT'] - table_mean_15['walk']) / table_mean_15['walk'] ) * 100

        table_median_15 = table_median_15.copy().iloc[:-1]
        table_median_15_decrease = table_median_15[['bike', 'walk_PT']].copy()
        table_median_15_decrease['bike'] = ((table_median_15['bike'] - table_median_15['walk']) / table_median_15['walk'] ) * 100
        table_median_15_decrease['walk_PT'] = ((table_median_15['walk_PT'] - table_median_15['walk']) / table_median_15['walk'] ) * 100

        # store results
        table_mean_decrease = table_mean_decrease.apply(pd.to_numeric)
        table_median_decrease = table_median_decrease.apply(pd.to_numeric)
        table_mean_decrease.round(2).to_csv(os.path.join(path_results, f'average_decrease_terrain_{terrain}.csv'))
        table_median_decrease.round(2).to_csv(os.path.join(path_results, f'median_decrease_terrain_{terrain}.csv'))

        table_mean_15_decrease = table_mean_15_decrease.apply(pd.to_numeric)
        table_median_15_decrease = table_median_15_decrease.apply(pd.to_numeric)
        table_mean_15_decrease.round(2).to_csv(os.path.join(path_results, f'15min_average_decrease_terrain_{terrain}.csv'))
        table_median_15_decrease.round(2).to_csv(os.path.join(path_results, f'15min_median_decrease_terrain_{terrain}.csv'))

print('done')