import requests
import os
import csv
from datetime import datetime, timedelta
import sys

# Přidání adresáře src do sys.path, aby bylo možné importovat moduly
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))

import database
import holidays

# Definice URL pro stahování dat
YEARLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/rok.txt"
MONTHLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/vybrane.txt"
DAILY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/denni_kurz.txt"

# Export cesty k databázovému souboru
DB_PATH = database.DB_PATH

# Global debug flag
DEBUG = False

def debug_print(*args, **kwargs):
    """Print debug messages only if debug mode is enabled."""
    if DEBUG:
        print(*args, **kwargs)

def set_debug_mode(debug):
    """Set the debug mode for this module."""
    global DEBUG
    DEBUG = debug

def is_yearly_data_complete(year, output_dir="data"):
    """
    Zkontroluje, zda roční data pro zadaný rok jsou kompletní podle kritérií:
    1. Poslední řádek obsahuje datum 31.12.rok
    2. První řádek obsahuje datum, který je ne-víkend a ne-svátek (1.1, 2.1, 3.1 nebo 4.1)
    
    :param year: Rok, který se má zkontrolovat.
    :param output_dir: Adresář, kde se nachází CSV soubor s ročními daty.
    :return: True pokud jsou data kompletní, jinak False.
    """
    filename = f"{year}.csv"
    filepath = os.path.join(output_dir, filename)
    
    # Zkontrolujeme, zda soubor existuje
    if not os.path.exists(filepath):
        debug_print(f"Soubor {filepath} neexistuje.")
        return False
    
    # Načteme data z CSV souboru
    try:
        with open(filepath, 'r', encoding='utf-8') as csvfile:
            # Použijeme csv.reader pro správné zpracování CSV souboru
            reader = csv.reader(csvfile, delimiter=',')
            lines = list(reader)
    except IOError as e:
        debug_print(f"Chyba při čtení souboru {filepath}: {e}")
        return False
    
    if len(lines) < 2:
        debug_print(f"Soubor {filepath} je prázdný nebo obsahuje pouze hlavičku.")
        return False
    
    # Získáme první a poslední datový řádek (přeskočíme hlavičku)
    first_data_line = None
    last_data_line = None
    
    # Najdeme první a poslední datový řádek
    for i in range(1, len(lines)):  # Začneme od indexu 1 (přeskočíme hlavičku)
        line = lines[i]
        if line and line[0]:  # Pokud řádek a první sloupec nejsou prázdné
            if not first_data_line:
                first_data_line = line
            last_data_line = line
    
    if not first_data_line or not last_data_line:
        debug_print(f"Soubor {filepath} neobsahuje žádná data.")
        return False
    
    # Zpracujeme první řádek
    try:
        first_date_str = first_data_line[0]  # Datum je vždy v prvním sloupci
        
        # Zkontrolujeme, zda první datum je 1.1., 2.1., 3.1. nebo 4.1. a je to pracovní den
        first_date = datetime.strptime(first_date_str, "%d.%m.%Y")
        if first_date.year != year:
            debug_print(f"První datum v souboru {filepath} není z roku {year}.")
            return False
            
        # Zkontrolujeme, zda první datum odpovídá našim kritériím
        valid_first_dates = []
        for day in range(1, 5):  # 1.1., 2.1., 3.1., 4.1.
            try:
                check_date = datetime(year, 1, day)
                check_date_str = check_date.strftime("%d.%m.%Y")
                # Zkontrolujeme, zda je to pracovní den (ne víkend a ne svátek)
                if not holidays.is_weekend(check_date_str) and not holidays.is_holiday(check_date_str):
                    valid_first_dates.append(check_date_str)
            except ValueError:
                # Může nastat pro neplatné datumy jako 29.2. v nepřestupném roce
                continue
        
        if first_date_str not in valid_first_dates:
            debug_print(f"První datum v souboru {filepath} ({first_date_str}) není platným prvním pracovním dnem roku.")
            return False
            
    except (ValueError, IndexError) as e:
        debug_print(f"Chyba při zpracování prvního řádku souboru {filepath}: {e}")
        return False
    
    # Zpracujeme poslední řádek
    try:
        last_date_str = last_data_line[0]  # Datum je vždy v prvním sloupci
        
        # Zkontrolujeme, zda poslední datum je 31.12.rok
        last_date = datetime.strptime(last_date_str, "%d.%m.%Y")
        expected_last_date = datetime(year, 12, 31)
        
        if last_date != expected_last_date:
            debug_print(f"Poslední datum v souboru {filepath} ({last_date_str}) není 31.12.{year}.")
            return False
            
    except (ValueError, IndexError) as e:
        debug_print(f"Chyba při zpracování posledního řádku souboru {filepath}: {e}")
        return False
    
    debug_print(f"Roční data pro rok {year} jsou kompletní.")
    return True

def check_yearly_data_consistency(year, output_dir="data"):
    """
    Zkontroluje, zda roční data pro zadaný rok obsahují záznamy za poslední 3 pracovní dny.
    
    :param year: Rok, pro který se má zkontrolovat konzistence dat.
    :param output_dir: Adresář, kde se nachází CSV soubor s ročními daty.
    :return: True pokud jsou data konzistentní, jinak False.
    """
    filename = f"{year}.csv"
    filepath = os.path.join(output_dir, filename)
    
    # Zkontrolujeme, zda soubor existuje
    if not os.path.exists(filepath):
        debug_print(f"Soubor {filepath} neexistuje.")
        return False
    
    # Načteme data z CSV souboru
    try:
        with open(filepath, 'r', encoding='utf-8') as csvfile:
            reader = csv.reader(csvfile)
            lines = list(reader)
    except IOError as e:
        debug_print(f"Chyba při čtení souboru {filepath}: {e}")
        return False
    
    if len(lines) < 2:
        debug_print(f"Soubor {filepath} je prázdný nebo obsahuje pouze hlavičku.")
        return False
    
    # Získáme seznam dat z CSV (první sloupec)
    dates_in_file = []
    for line in lines[1:]:  # Přeskočíme hlavičku
        if line and line[0]:  # Zkontrolujeme, že řádek a první sloupec nejsou prázdné
            dates_in_file.append(line[0])
    
    if not dates_in_file:
        debug_print(f"Soubor {filepath} neobsahuje žádná data.")
        return False
    
    # Zkontrolujeme poslední 3 pracovní dny
    today = datetime.now()
    checked_dates = []
    
    # Projdeme posledních 7 dní (pro jistotu) a vybereme 3 pracovní dny
    current_date = today - timedelta(days=1)  # Začneme včerejškem
    days_checked = 0
    
    while len(checked_dates) < 3 and days_checked < 7:
        date_str = current_date.strftime("%d.%m.%Y")
        
        # Zkontrolujeme, zda je to pracovní den (není víkend ani svátek)
        if not holidays.is_weekend(date_str) and not holidays.is_holiday(date_str):
            # Zkontrolujeme, zda je rok správný
            try:
                date_obj = datetime.strptime(date_str, "%d.%m.%Y")
                if date_obj.year == year:
                    checked_dates.append(date_str)
            except ValueError:
                pass
        
        current_date -= timedelta(days=1)
        days_checked += 1
    
    # Pokud nemáme žádné pracovní dny k ověření, vrátíme True (nemáme co kontrolovat)
    if not checked_dates:
        debug_print(f"Pro rok {year} nebyly nalezeny žádné pracovní dny k ověření v posledním týdnu.")
        return True
    
    # Zkontrolujeme, zda všechny pracovní dny jsou v souboru
    missing_dates = []
    for date_str in checked_dates:
        if date_str not in dates_in_file:
            missing_dates.append(date_str)
    
    if missing_dates:
        debug_print(f"V souboru {filepath} chybí záznamy pro následující pracovní dny: {', '.join(missing_dates)}")
        return False
    else:
        debug_print(f"Roční data pro rok {year} jsou konzistentní.")
        return True

def download_yearly_data(year, output_dir="data", force=False):
    """
    Stáhne roční data z CNB a uloží je do CSV souboru a databáze.

    :param year: Rok, pro který se mají stáhnout data (např. 2020).
    :param output_dir: Adresář, kam se má CSV soubor uložit.
    :param force: Pokud je True, data se stáhnou i v případě, že již existují a jsou konzistentní.
    :return: Cesta k vytvořenému CSV souboru.
    """
    # Pokud není vynucené stahování, zkontrolujeme, zda existující data jsou kompletní
    if not force:
        # Zkontrolujeme, zda soubor existuje a je kompletní
        if is_yearly_data_complete(year, output_dir):
            debug_print(f"Roční data pro rok {year} jsou kompletní. Není nutné je stahovat znovu.")
            return os.path.join(output_dir, f"{year}.csv")
        else:
            debug_print(f"Roční data pro rok {year} nejsou kompletní. Stahuji znovu...")
    
    url = f"{YEARLY_DATA_URL}?rok={year}"
    debug_print(f"Stahuji data z: {url}")

    try:
        response = requests.get(url)
        response.raise_for_status()  # Vyvolá výjimku pro chybné HTTP kódy
    except requests.exceptions.RequestException as e:
        debug_print(f"Chyba při stahování dat: {e}")
        return None

    # Vytvoření jména souboru
    filename = f"{year}.csv"
    filepath = os.path.join(output_dir, filename)

    # Zpracování dat a uložení do CSV
    lines = response.text.strip().split('\n')
    if not lines:
        debug_print("Stažený soubor je prázdný.")
        return None

    # První řádek obsahuje hlavičku
    header = lines[0].split('|')
    # Převod názvů sloupců do formátu vhodného pro CSV (např. nahrazení mezer podtržítky)
    header = [col.replace(' ', '_').replace('-', '_') for col in header]

    # Zpracování datových řádků
    data_rows = []
    for line in lines[1:]:
        if not line.strip():
            continue
        # Nahrazení českých desetinných čárek za tečky
        row = [item.replace(',', '.') for item in line.split('|')]
        data_rows.append(row)
        
        # Uložení do databáze
        date_str = row[0]  # Datum je vždy v prvním sloupci
        for i in range(1, len(header)):
            col_name = header[i]
            if col_name == "Datum":
                continue
            
            # Název sloupce je ve formátu "1_USD", "100_JPY" atd.
            # Rozdělíme ho na množství a kód měny
            parts = col_name.split('_')
            if len(parts) >= 2:
                try:
                    amount = int(parts[0])
                    currency_code = '_'.join(parts[1:])  # Pro případ měn se složeným názvem
                    rate = float(row[i])
                    database.insert_rate(date_str, currency_code, amount, rate)
                except (ValueError, IndexError):
                    # Přeskočit sloupce, které nelze parsovat
                    continue

    # Zápis do CSV souboru
    try:
        with open(filepath, 'w', newline='', encoding='utf-8') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(header)
            writer.writerows(data_rows)
        debug_print(f"Data byla úspěšně uložena do: {filepath}")
        return filepath
    except IOError as e:
        debug_print(f"Chyba při zápisu do souboru: {e}")
        return None

def download_monthly_data(currency_code, start_date, end_date, output_dir="data"):
    """
    Stáhne měsíční data pro zadanou měnu a časové období z CNB a uloží je do CSV souboru a databáze.

    :param currency_code: Kód měny (např. USD).
    :param start_date: Počáteční datum ve formátu DD.MM.YYYY.
    :param end_date: Koncové datum ve formátu DD.MM.YYYY.
    :param output_dir: Adresář, kam se má CSV soubor uložit.
    :return: Chta k vytvořenému CSV souboru.
    """
    url = f"{MONTHLY_DATA_URL}?od={start_date}&do={end_date}&mena={currency_code}&format=txt"
    debug_print(f"Stahuji data z: {url}")

    try:
        response = requests.get(url)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        debug_print(f"Chyba při stahování dat: {e}")
        return None

    # Vytvoření jména souboru
    filename = f"{start_date.replace('.', '_')}_to_{end_date.replace('.', '_')}_{currency_code}.csv"
    filepath = os.path.join(output_dir, filename)

    # Zpracování dat a uložení do CSV
    lines = response.text.strip().split('\n')
    if not lines:
        debug_print("Stažený soubor je prázdný.")
        return None

    # První řádek obsahuje informace o měně, druhý hlavičku dat
    currency_info = lines[0]
    header = lines[1].split('|')
    header = [col.replace(' ', '_').replace('-', '_') for col in header]

    # Zpracování datových řádků
    data_rows = []
    for line in lines[2:]:
        if not line.strip():
            continue
        row = [item.replace(',', '.') for item in line.split('|')]
        data_rows.append(row)
        
        # Uložení do databáze
        # Formát řádku: Datum|Kurz
        if len(row) >= 2:
            date_str = row[0]
            try:
                # Z currency_info získáme množství
                # Příklad: "Měna: USD|Množství: 1"
                parts = currency_info.split('|')
                amount_part = next((p for p in parts if p.startswith("Množství:")), None)
                if amount_part:
                    amount = int(amount_part.split(':')[1].strip())
                    rate = float(row[1])
                    database.insert_rate(date_str, currency_code, amount, rate)
            except (ValueError, IndexError):
                debug_print(f"Chyba při parsování řádku: {line}")

    # Zápis do CSV souboru
    try:
        with open(filepath, 'w', newline='', encoding='utf-8') as csvfile:
            csvfile.write(f"{currency_info}\n")  # Uložení informací o měně
            writer = csv.writer(csvfile)
            writer.writerow(header)
            writer.writerows(data_rows)
        debug_print(f"Data byla úspěšně uložena do: {filepath}")
        return filepath
    except IOError as e:
        debug_print(f"Chyba při zápisu do souboru: {e}")
        return None

def download_daily_data(date, output_dir="data"):
    """
    Stáhne denní data z CNB pro zadané datum a uloží je do CSV souboru a databáze.

    :param date: Datum ve formátu DD.MM.YYYY.
    :param output_dir: Adresář, kam se má CSV soubor uložit.
    :return: Cesta k vytvořenému CSV souboru.
    """
    url = f"{DAILY_DATA_URL}?date={date}"
    debug_print(f"Stahuji data z: {url}")

    try:
        response = requests.get(url)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        debug_print(f"Chyba při stahování dat: {e}")
        return None

    # Vytvoření jména souboru
    filename = f"daily_{date.replace('.', '_')}.csv"
    filepath = os.path.join(output_dir, filename)

    # Zpracování dat a uložení do CSV
    lines = response.text.strip().split('\n')
    if not lines:
        debug_print("Stažený soubor je prázdný.")
        return None

    # První řádek obsahuje datum a číslo, druhý hlavičku
    date_info = lines[0]
    header = lines[1].split('|')
    header = [col.replace(' ', '_').replace('-', '_') for col in header]

    # Zpracování datových řádků
    data_rows = []
    for line in lines[2:]:
        if not line.strip():
            continue
        row = [item.replace(',', '.') for item in line.split('|')]
        data_rows.append(row)
        
        # Uložení do databáze
        # Formát řádku: země|měna|množství|kód|kurz
        if len(row) >= 5:
            try:
                # country = row[0]
                # currency_name = row[1]
                amount = int(row[2])
                currency_code = row[3]
                rate = float(row[4])
                database.insert_rate(date, currency_code, amount, rate)
            except (ValueError, IndexError):
                debug_print(f"Chyba při parsování řádku: {line}")

    # Zápis do CSV souboru
    try:
        with open(filepath, 'w', newline='', encoding='utf-8') as csvfile:
            csvfile.write(f"{date_info}\n")  # Uložení informací o datu
            writer = csv.writer(csvfile)
            writer.writerow(header)
            writer.writerows(data_rows)
        debug_print(f"Data byla úspěšně uložena do: {filepath}")
        return filepath
    except IOError as e:
        debug_print(f"Chyba při zápisu do souboru: {e}")
        return None

# Příklad použití
if __name__ == "__main__":
    # Pro testování lze spustit tento skript samostatně
    database.init_db()
    downloaded_file = download_yearly_data(2020)
    if downloaded_file:
        debug_print(f"Stažený soubor: {downloaded_file}")
    else:
        debug_print("Stažení se nezdařilo.")