"""
Funciones ordenadas que contiene este fichero:
· setup_mainURL
· process_entry
· initialize_img
· check_response
· get_page_links
· get_data_from_entry
· download_img
· get_extra_data
"""

# Importamos librerías necesarias.
from bs4 import BeautifulSoup
import pandas as pd
import os
import requests
import sys


def setup_mainURL():
    """
    Esta función lee el primer argumento pasado
    mediante la línea de comando utilizada para
    ejectuar el presente programa y proporciona la
    URL de la página web a la que realizar web scraping.

    Return:
    - url (str): URL de la página web.
    """
    # Argumentos en la línea de comandos.
    args = sys.argv

    if len(args)>1:
        nationality_name = args[1]

        # Todas las nacionalidades.
        if args[1].lower() in  ['todos', 'todas']:
            nationality_option = 0

        # Con nacionalidad española.
        elif args[1].lower() in ['españa', 'española']:
            nationality_option = 1

        # Otra opción no sería válida.
        else:
            raise Exception(
                    f"Opción 'args[1]' no disponible. Prueba 'Todos' o 'España'")
    else:
        # Por defecto con nacionalidad española.
        nationality_option = 1

    # Parámetros para seleccionar nacionalidad mediante la URL.
    ids = [0, 157]
    id_nat = ids[nationality_option]

    # Sustituye id_nat en la URL.
    url = f"https://www.transfermarkt.es/spieler-statistik/wertvollstespieler/marktwertetop/plus/0/galerie/0?ausrichtung=alle&spielerposition_id=alle&altersklasse=alle&jahrgang=0&land_id={id_nat}&kontinent_id=0&yt0=Mostrar"
    return url


def process_entry(entry, headers, i=0):
    """
    Esta función procesa cada fila/entry de la tabla de
    la página web para extraer los siguientes datos.
    - Nombre de jugador.
    - Posición.
    - Edad.
    - Nacionalidades.
    - Club al que pertenece
    - Valor de mercado.
    - URL de imagen de perfil.
    - Código de jugador en transfermarkt.com.
    - Altura en m.
    - Proveedor.
    - Pie (zurdo o diestro)
    Se utiliza la función get_data_from_entry para ello. A continuación,
    descarga la imagen de perfil del jugador y entra en la página web
    del propio jugador para añadir los datos de proveedor y pie.

    Arguments:
    - entry (BeautilSoup object): fila de jugador extraída con BeautifulSoup.
    - headers (str): user-agent para utilizar requests.
    - i (int): índice del jugador dentro de la tabla para ordenarlo, en caso
         de paralelización.

    Returns:
    - player (dict): diccionario con datos del jugador.
    - i (int): índice del jugador dentro de la tabla para ordenarlo, en caso
         de paralelización.
    """
    # Scrape entry of principle page
    player = get_data_from_entry(entry)

    # Descargamos la imagen del jugador.
    download_img(player["Name"], player["Image"], headers)

    # Para pie, altura y poveedor hay que entrar en la página del jugador.
    url = "https://www.transfermarkt.es/lamine-yamal/profil/spieler/"\
            +player["Code"]

    altura, proveedor, pie = get_extra_data(url, headers)
    player["Altura"] = altura
    player["Proveedor"] = proveedor
    player["Pie"] = pie

    return player, i


def initialize_img():
    """
    Si la carpeta ./images no existe, la crea.
    """
    if not os.path.exists('images'):
        os.makedirs('images')


def check_response(response):
    """
    Si la respuesta utilizando requests al acceder a la página
    web no tiene código 200, devuelve Exeption.

    Arguments:
    - response:
    """
    url = response.url
    # Verificamos que se ha accedido bien a la página.
    if response.status_code != 200:
        raise Exception("No se ha podido acceder a la siguiente página\n", url)


def get_page_links(soup):
    """
    Obtenemos los enlaces para acceder a las distintas
    páginas de la responsive table. Las 10 primeras solo.

    Arguments:
    - soup (BeautifulSoup object): página web pasada a BeautifulSoup.

    Returns:
    - page_links (list): lista con los links en formato string.
    """
    pager_div = soup.select_one("div.pager ul")

    # URL base al que añadir sufijos para entrar a subdominios.
    base_url = "https://www.transfermarkt.es"

    # Links completos.
    page_links = [base_url + url["href"] for url in pager_div.select("li a")[:10]]
    return page_links


def get_data_from_entry(entry):
    """
    Esta función se encarga de extraer todos los datos
    de un jugador contenidos en la página web principal, donde
    se muestran ordenados según su valor de mercado.

    Arguments:
    - entry (BeautifulSoup object): fila (entry) jugador obtenida
      mediante BeautifulSoup a partir del HTML descargado de la página web
      principal.

    Returns:
    - player (dict): diccionario representando jugador con todos su datos.
    """

    # Accede a la tabla con los datos.
    player_info = entry.find("table", class_="inline-table")

    # Nombre del jugador.
    player_name_tag = player_info.find("td", class_="hauptlink").find("a")
    player_name = player_name_tag.text.strip() \
                    if player_name_tag else "Nan"

    # Código de jugador en transfermarkt.
    player_code = player_name_tag["href"].strip().split('/')[-1]

    # Posición de jugador.
    position_tag = player_info.find_all("tr")[1].find("td")
    position = position_tag.text.strip() \
            if position_tag else "Nan"

    # Edad.
    age_tag = entry.find("td",
             class_="zentriert").find_next_sibling("td", class_="zentriert")
    age = age_tag.text.strip() if age_tag else "Nan"

    # Nacionalidades.
    nationality_tags = entry.find_all("img", class_="flaggenrahmen")
    nationalities = ', '.join([img['title'] for img in nationality_tags \
            if 'title' in img.attrs])

    # Club.
    club_tag = entry.find("td", class_="zentriert").find_next_sibling("td",
            class_="zentriert").find_next_sibling("td", 
                class_="zentriert").find_next_sibling("td", class_="zentriert")
    club_link = club_tag.find("a")
    club = club_link["title"] if club_link else "Nan"

    # Valor de mercado.
    market_value_tag = entry.find_all("td")[-1]
    market_value_text = market_value_tag.text.strip() \
            if market_value_tag else "0 mill. €"
    market_value = market_value_text.replace(' mill. €', '')\
            .replace('.', '').replace(',', '.')

    # URL para descargar imagien de jugador.
    img_tag = player_info.find("img", class_="bilderrahmen-fixed")
    img_url = img_tag['src'] if img_tag else None

    # Crea diccionario para guardar todos los datos.
    player = {
            "Name": player_name,
            "Position": position,
            "Age": age,
            "Nationalities": nationalities,
            "Club": club,
            "Market_value": market_value,
            "Image": img_url,
            "Code": player_code}

    return player


def download_img(player_name, img_url, headers):
    if img_url is None:
        return

    try:
        img_response = requests.get(img_url, headers=headers)

        if img_response.status_code == 200:
            img_filename = os.path.join('images',
                            f"{player_name.replace(' ', '_')}.jpg")
        else:
            return

        with open(img_filename, 'wb') as img_file:
            img_file.write(img_response.content)

        print(f"Imagen guardada: {img_filename}")
    except requests.exceptions.RequestException as e:
        print(f"Imagen {img_url} no descargada debido a \n{e}")


def get_extra_data(url, headers):
    """
    Esta función se utiliza para entrar a la URL de la página
    especifica de cada jugador y extraer los siguientes datos:
    altura, proveedor y pie.

    Arguments:
    - url (str): dirección URL de la página del jugador.
    - headers (str): user-agent para descargar la página.

    Returns:
    - (altura, proveedor, pie) (tuple): tuple con los datos del jugador.
    """
    
    # Descarga la página del jugador.
    response = requests.get(url, headers=headers)
    check_response(response)

    # Inicializa BeautifulSoup para gestionarla.
    soup = BeautifulSoup(response.content, "html.parser")

    # Tabla con los datos que buscamos.
    table = soup.find("div", class_="info-table")

    # Obtén proveedor.
    proveedor = table.find("span", string="Proveedor:")
    if proveedor:
        proveedor = proveedor.find_next("span").text.strip()
    else:
        proveedor = "Nan"

    # Obtén altura.
    altura = table.find("span", string="Altura:")
    if altura:
        altura = float(altura.find_next("span").text.strip()\
                .split()[0].replace(',','.'))
    else:
        altura = "Nan"

    # Obtén pie.
    pie = table.find("span", string="Pie:")
    if pie:
        pie = pie.find_next("span").text.strip()\
                .split()[0].replace(',','.')
    else:
        pie = "Nan"

    return (altura, proveedor, pie)
