import io
import shutil

from PIL import Image, UnidentifiedImageError
import requests
import os

from requests.exceptions import InvalidURL, MissingSchema
from unidecode import unidecode
import math
import zipfile
import sys


def get_team(params) -> list:
    token = 'admin'
    headers = {'X-API-KEY': token}
    farmname = os.environ.get('FARMNAME')
    full_url = 'https://gwpa.' + str(farmname) + '.k8.catchmedia.com/ws/api/v1/admin/player'

    response = requests.get(full_url, params=params, headers=headers)
    if response.status_code != 200:
        print("Failed to retrieve")
    return response.json()


def create_clean_to_unclean_dict(input) -> dict:
    clean_to_unclean_dict = {}
    converted_list = [unidecode(string) for string in input]
    uppercase_list = [string.upper() for string in converted_list]

    for i in range(0, len(uppercase_list)):
        clean_to_unclean_dict[uppercase_list[i]] = input[i]
    return clean_to_unclean_dict


def player_to_dict(list_of_names) -> dict:
    players_dict = {}
    for player in list_of_names:
        current_player = unidecode(player['player_name'].upper())
        current_player = current_player.replace(",", "")
        split_name = current_player.split()
        if (len(split_name) > 1):
            players_dict[split_name[1] + " " + split_name[0]] = player
        else:
            players_dict[current_player] = player
    return players_dict


def exists(substring, list_of_strings):
    for player_name in list_of_strings.keys():
        if substring in player_name:
            return list_of_strings[player_name]
    return None


def find_last_string(substring, list_of_strings):
    # Method returns the last string in the list of strings that contains the substring in it
    temp_string = ""
    for string in list_of_strings:
        if substring in string:
            temp_string = string
    return temp_string if not None else None


def get_image_path(base_path, image_path) -> str:
    folder_path = os.path.join(base_path, image_path)
    image_name = find_last_string('003_000.png', os.listdir(folder_path))
    full_path = os.path.join(folder_path, image_name)
    return full_path


def resize_image(path, scale_parameter):
    try:
        image = Image.open(path)
        # Shrink image dimensions by %60 (Initial size - .6 initial size)
        updated_image_size = tuple([math.trunc(number * (1 - scale_parameter)) for number in image.size])

        # Shrink actual image using dimensions defined above
        image.thumbnail(updated_image_size)
    except FileNotFoundError:
        print("Error: The file '{}' does not exist.".format(path))
        return -1
    except PermissionError:
        print("Error: Permission denied while accessing the file '{}'.".format(path))
        return -1
    except UnidentifiedImageError:
        print("Error: The file '{}' is not a recognized image format or is corrupted.".format(path))
        return -1
    except IsADirectoryError:
        print("Error: The file '{}' is a directory")
        return -1
    except Exception as e:
        print("An unexpected error occurred:", str(e))
        sys.exit()
    return image


def post_image(player, image) -> list:
    # Url for the request
    farmname = os.environ.get('FARMNAME')
    full_url = 'https://gwpa.' + str(farmname) + '.k8.catchmedia.com/ws/api/v1/admin/images'

    # Headers for the request
    headers = {'X-API-KEY': "admin"}

    # Create a file for the request
    # Convert the Image object to a byte-like object
    image_bytes = io.BytesIO()
    image.save(image_bytes, format='PNG')
    image_bytes.seek(0)

    files = {'file': (player['player_name'] + '.png', image_bytes, 'image/png')}

    # Create params
    data = {
        'assetTypeID': '5',  # Replace with the actual assetTypeID value
        'imageObjectID': player['id']  # Replace with the actual imageObjectID value
    }

    # Send the POST request
    response = requests.post(full_url, data=data, files=files, headers=headers)
    return response.json()


def put_player(player, public_url):
    farmname = os.environ.get('FARMNAME')
    url = 'https://gwpa.' + str(farmname) + '.k8.catchmedia.com/ws/api/v1/admin/player/' + str(player['id'])

    headers = {'X-API-KEY': "admin", }

    params = {'id': player['id']}

    player['img_url'] = public_url

    response = requests.put(url, json=player, headers=headers, params=params)
    return response


def get_player_mapping(external_id, league_id, data_source_id):
    url = 'https://gwpa.rnd.k8.catchmedia.com/ws/api/v1/admin/identifiers-mapping'
    params = {'object_type_id': '4', 'data_source_id': str(data_source_id), 'external_id': external_id,
              'league_id': league_id}
    headers = {'accept': 'application/json', 'X-API-KEY': 'admin'}

    response = requests.get(url, params=params, headers=headers)
    return response.json()


def get_player_by_id(player_id):
    url = 'https://gwpa.rnd.k8.catchmedia.com/ws/api/v1/admin/player/' + str(player_id)
    headers = {'accept': 'application/json', 'X-API-KEY': 'admin'}

    response = requests.get(url, headers=headers)
    return response.json()


def upload_images_by_team(mode, league_id, team_id, images_file_path, scale_parameter, data_source_id):
    # Get team that needs images to be updated
    params = {'league_id': league_id, 'team_id': team_id}

    catch_media_results = get_team(params)
    catch_media_results_dict = player_to_dict(catch_media_results)

    # Get a dict of the names of the images for that team
    image_results = create_clean_to_unclean_dict(os.listdir(images_file_path))

    for player_image in image_results.keys():
        found = exists(player_image, catch_media_results_dict)

        if found is not None:
            print("Hit: " + player_image)  # + " id: " + str(found['id']))
            if mode != '-f' and found['img_url'] is not None:
                continue

            upload_player_image(found, image_results, images_file_path, player_image, scale_parameter)

        else:
            # GET the player that is mapped to the current player_image
            mapped_response = get_player_mapping(player_image, league_id, data_source_id)
            # IF the player is not mapped to
            if len(mapped_response) == 0:
                print("Miss: " + player_image)
                continue

            print("Hit through mapping: " + player_image)
            # Take the external id and get the player from swagger
            player_id = mapped_response[0]['pa_id']
            found = get_player_by_id(player_id)
            if mode != '-f' and found['img_url'] is not None:
                continue

            # Call upload_image_for_player with the value of 'found' being the external name
            upload_player_image(found, image_results, images_file_path, player_image, scale_parameter)


def upload_player_image(found, image_results, images_file_path, player_image, scale_parameter):
    # Get the path to the folder of the image of the player_image
    full_image_path = get_image_path(images_file_path, image_results[player_image])
    # Shrink the image
    resized_image = resize_image(full_image_path, scale_parameter)
    if resized_image == -1:
        print("Failed image upload")
        return
    # Upload image and get a dictionary back in json format as a response
    response = post_image(found, resized_image)
    # Take the "image_cdn_url" (public url) from the response
    public_image_url = response['latest']['image_cdn_url']
    # Put this ""image_cdn_url" into the player (value of found is the player's list) and update the player
    response = put_player(found, public_image_url)
    print("Success image upload") if response.status_code == 200 else print("Failed image upload")


def get_list_of_teams(league_id):
    farmname = os.environ.get('FARMNAME')
    url = 'https://gwpa.' + str(farmname) + '.k8.catchmedia.com/ws/api/v1/admin/team'

    params = {'league_id': str(league_id)}

    headers = {'X-API-KEY': 'admin'}

    response = requests.get(url, params=params, headers=headers)
    if response.status_code == 200:
        print("Team retrieval success")
    else:
        print("Team retrieval failure")
        sys.exit()

    return response


def unpack_league_path(path) -> str:
    try:
        # Unpacks the given path and returns the path to the new unpacked directory
        # If path is a zipfile extract the zip file
        with zipfile.ZipFile(path, 'r') as zip:
            zip.extractall(os.path.dirname(path))

        # Get the name of the file that was just unzipped using zip.namesList
        parent_dir = os.path.dirname(path)
        new_file_name = zip.namelist()[0]
        new_path = os.path.join(parent_dir, new_file_name)

        return new_path
    except (FileNotFoundError, zipfile.BadZipFile):
        print("File path not found or bad zip file")
        print(
            "Please provide the correct file path in the following format: mode league_id scale_parameter "
            "data_source_id 'filepath'")
        sys.exit()


def find_team(current_team, list_of_teams) -> str:  # Needs to be tested
    for team in list_of_teams:
        if team in current_team:
            print("Found: " + team)
            return team
    print("Current team: " + current_team + " not found")
    return ""


def download_images_url(url):
    # Downloads the url and returns the path to that downloaded url
    print('Beginning images download')
    try:
        response = requests.get(url)
    except (InvalidURL, MissingSchema):
        print("Invalid URL passed\nPlease provide a valid url for download\nImages download failed")
        sys.exit()

    new_dir = '/tmp'
    if not os.path.isdir(new_dir):
        os.makedirs(new_dir)

    file_path = os.path.join(new_dir, url.split('/')[-1])
    with open(file_path, "wb") as file:
        file.write(response.content)

    print('Images download complete')
    return file_path


def unpack_all_paths_in_directory(directory) -> str:
    sub_dirs = os.listdir(directory)

    if not os.path.isdir(os.path.join(directory, 'teams')):
        os.makedirs(os.path.join(directory, 'teams'))

    # Loop through all teams.zip in directory
    for sub_dir in sub_dirs:
        if sub_dir[0] == '.':
            continue
        # Create a new dir for current team in /teams
        if not os.path.isdir(os.path.join(directory + '/teams', sub_dir.split('.')[0])):
            os.makedirs(os.path.join(directory + '/teams', sub_dir.split('.')[0]))

        # Unpack each sub_dir.zip
        path = os.path.join(directory, sub_dir)
        if os.path.isfile(path) and path.endswith('.zip'):
            unpack_team_path(os.path.join(directory, sub_dir))
    return os.path.join(directory, 'teams')


def unpack_team_path(path):
    try:
        # Unpacks the given path and returns the path to the new unpacked directory
        # If path is a zipfile extract the zip file
        with zipfile.ZipFile(path, 'r') as zip:
            path = os.path.join(os.path.dirname(path), 'teams', os.path.splitext(path.split('/')[-1])[0])
            zip.extractall(path)
            remove_llfolder(path)

    except (FileNotFoundError, zipfile.BadZipFile):
        print("File path not found or bad zip file")
        print("Please provide the correct file path in the following format: -f/-s league_id 'filepath'")
        sys.exit()


def remove_llfolder(path):
    # Find the 'WEB_LA_LIGA' dir
    for sub_dir in os.listdir(path):
        if 'WEB' in sub_dir:
            print("Swapping WEB LA LIGA dir")
            for player in os.listdir(os.path.join(path, sub_dir)):
                # Move the contents of 'WEB_LA_LIGA' to the parent folder (team_name)
                original = os.path.join(path, sub_dir, player)
                target = os.path.join(path, player)
                if not os.path.isdir(target):
                    shutil.move(original, target)


def upload_images_by_league(mode, league_id, images_url, scale_parameter, data_source_id):
    response = get_list_of_teams(league_id)

    images_file_path = download_images_url(images_url)

    unpacked_league_path = unpack_league_path(images_file_path)
    unpacked_images_file_path = unpack_all_paths_in_directory(unpacked_league_path)
    # FOR loop through the list of teams
    for team in response.json():
        current_team_name = team['name']
        print("Looking for: " + current_team_name)

        current_team_folder_name = find_team(current_team_name, os.listdir(unpacked_images_file_path))
        if len(current_team_folder_name) == 0:
            continue

        # Get the file path for that team
        current_team_path = os.path.join(unpacked_images_file_path, current_team_folder_name)

        # Call upload_images_by_team and pass in league_id, team_id, and path for that team
        upload_images_by_team(mode, str(league_id), str(team['id']), current_team_path, scale_parameter,
                              data_source_id)


def main(args):
    try:
        mode = str(args[0])
        league_id = int(args[1])
        scale_parameter = float(args[2])
        data_source_id = int(args[3])
        images_url = str(args[4])

    except (IndexError, ValueError):
        print("Invalid arguments passed")
        print(
            "Please provide the required arguments in the correct format: file_name mode league_id scale_parameter "
            "data_source_id 'filepath'")
        sys.exit()

    upload_images_by_league(mode, league_id, images_url, scale_parameter, data_source_id)
    print("League upload finished")


if __name__ == '__main__':
    #os.environ['FARMNAME'] = 'rnd'
    main(sys.argv[1:])

'''
python3 upload_images_script_local.py -nf 6 .6 10003 'auto download link to .zip'


La Liga File Path
LaLiga/teams.zip->WEB LA LIGA/player_name/images
I need to unzip LaLiga
Unzip a team go through all the files of that team, delete the directory of WEB LA LIGA, then move all the files into a new directory I make called the team name
'''
