import os
import shutil
import time
from pathlib import Path

import mysql.connector
import requests
from dotenv import load_dotenv
from mysql.connector import Error
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.firefox import GeckoDriverManager

load_dotenv()

GECKODRIVER_PATH = Path("/usr/local/bin/geckodriver")
FIREFOX_PROFILE_DIR = Path("/tmp")
FIREFOX_PROFILE_PREFIX = "rust_mozprofile"
STALE_PROFILE_MAX_AGE_SECONDS = 6 * 60 * 60


def _cleanup_stale_firefox_profiles(max_age_seconds=STALE_PROFILE_MAX_AGE_SECONDS):
    # Remove old geckodriver temp profiles so /tmp cannot grow forever.
    now = time.time()
    for profile_dir in FIREFOX_PROFILE_DIR.glob(f"{FIREFOX_PROFILE_PREFIX}*"):
        try:
            if not profile_dir.is_dir():
                continue
            if now - profile_dir.stat().st_mtime < max_age_seconds:
                continue
            shutil.rmtree(profile_dir, ignore_errors=True)
        except OSError:
            # Ignore cleanup issues and let the next run retry.
            continue


def _close_driver(driver):
    # quit() closes all windows and ends geckodriver cleanly.
    try:
        driver.quit()
    except Exception as error:
        print(f"driver.quit() failed: {error}")

def _create_driver():
    # Clean stale temporary profiles left behind by previous failed runs.
    _cleanup_stale_firefox_profiles()

    options = webdriver.FirefoxOptions()
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument("--window-size=1920,1200")
    options.binary_location = "/usr/bin/firefox"

    if GECKODRIVER_PATH.exists():
        service = FirefoxService(executable_path=str(GECKODRIVER_PATH))
    else:
        # Fallback keeps compatibility if an older image is missing geckodriver.
        service = FirefoxService(executable_path=GeckoDriverManager().install())

    return webdriver.Firefox(service=service, options=options)

def get_cookies():
    driver = _create_driver()
    cookies = []
    try:
        driver.get("https://b2bpartnerportal.com/")

        user = driver.find_element(By.ID, 'username')
        user.send_keys(os.environ.get('mol_user'))
        password = driver.find_element(By.ID, 'password')
        password.send_keys(os.environ.get('mol_pw'))
        button = driver.find_element(By.ID, 'login-button')
        button.click()

        # Wait until the SPA sets the auth_token cookie (up to 20s).
        WebDriverWait(driver, 20).until(lambda d: any(c.get('name') == 'auth_token' for c in d.get_cookies()))

        # Navigate to SPA root to ensure CSRF/JSESSION are initialized.
        driver.get("https://b2bpartnerportal.com/occ/")

        # Then navigate to pricing details filter page to ensure the correct context.
        driver.get("https://b2bpartnerportal.com/occ/#/customers/pricing-details/customer/1/1")

        # Give the app a moment to finalize cookies/session propagation.
        WebDriverWait(driver, 10).until(lambda d: any(c.get('name') == 'auth_token' for c in d.get_cookies()))

        cookies = driver.get_cookies()
    finally:
        _close_driver(driver)
        _cleanup_stale_firefox_profiles()
    
    cookies_str = '; '.join([f"{cookie['name']}={cookie['value']}" for cookie in cookies])

    csrf_token = ""
    for cookie in cookies:
        if cookie['name'] == "CSRF-TOKEN":
            csrf_token = cookie["value"]

    print(cookies_str)
    return cookies_str, csrf_token

def fetch_values_in_page(product_codes):
    driver = _create_driver()
    try:
        driver.get("https://b2bpartnerportal.com/")
        user = driver.find_element(By.ID, 'username')
        user.send_keys(os.environ.get('mol_user'))
        password = driver.find_element(By.ID, 'password')
        password.send_keys(os.environ.get('mol_pw'))
        button = driver.find_element(By.ID, 'login-button')
        button.click()

        WebDriverWait(driver, 20).until(lambda d: any(c.get('name') == 'auth_token' for c in d.get_cookies()))

        driver.get("https://b2bpartnerportal.com/occ/")
        driver.get("https://b2bpartnerportal.com/occ/#/customers/pricing-details/customer/1/1")
        WebDriverWait(driver, 10).until(lambda d: any(c.get('name') == 'CSRF-TOKEN' for c in d.get_cookies()))

        results = {}
        for code in product_codes:
            script = """
            const done = arguments[0];
            try {
              const getCookie = (name) => (document.cookie.split('; ').find(c => c.startsWith(name + '=')) || '').split('=')[1] || '';
              const csrf = decodeURIComponent(getCookie('CSRF-TOKEN'));
              const now = new Date();
              const end = new Date(now);
              end.setHours(23,59,59,999);
              const start = new Date(now);
              start.setDate(start.getDate() - 90);
              start.setHours(0,0,0,0);
              const payload = {
                page: 0,
                itemsPerPage: 10,
                filter: {
                  lpProductCode: [arguments[1]],
                  networkCode: ["MOLH_NETWRK"],
                  fcmsId: "330059510H",
                  validFrom: start.toISOString(),
                  validUntil: end.toISOString(),
                },
                order: [{ columnCode: "companyCode", direction: "ASC" }]
              };
              fetch("https://b2bpartnerportal.com/occ/customer-service/api/list-price/list", {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  "Accept": "application/json, text/plain, */*",
                  "X-CSRF-TOKEN": csrf,
                  "X-User-Mode": "EXTERNAL_MODE"
                },
                body: JSON.stringify(payload),
                credentials: "include"
              }).then(r => r.json()).then(data => {
                try {
                  const amount = data && data.content && data.content[0] && data.content[0].lpAmount && data.content[0].lpAmount.amount;
                  done({ ok: true, amount: amount || 0 });
                } catch(e) {
                  done({ ok: false, error: String(e) });
                }
              }).catch(e => done({ ok: false, error: String(e) }));
            } catch (e) {
              done({ ok: false, error: String(e) });
            }
            """
            # Extend async script timeout to 60s
            driver.set_script_timeout(60)
            res = driver.execute_async_script(script, code)
            if isinstance(res, dict) and res.get('ok'):
                results[code] = str(res.get('amount', 0))
            else:
                print(f"In-page fetch failed for {code}: {res}")
                results[code] = "0"
        return results
    finally:
        _close_driver(driver)
        _cleanup_stale_firefox_profiles()

def get_session_id(cookies_str):
    session_id = None
    try:
        headers = {
            'Accept': 'application/json,text/plain,application/octet-stream',
            'Accept-Language': 'en-US,en;q=0.9,hu;q=0.8,de;q=0.7',
            'Cache-Control': 'no-cache',
            'Pragma': 'no-cache',
            'Connection': 'keep-alive',
            'Referer': 'https://b2bpartnerportal.com/occ/',
            'Origin': 'https://b2bpartnerportal.com',
            'Cookie': cookies_str,
        }
        response = requests.get('https://b2bpartnerportal.com/occ/localization-service/api/localization/initialization/DESKTOP', headers=headers, timeout=20)
        response.raise_for_status()
        
        # Some backends may return empty body with 204 or text; guard JSON parsing
        if response.headers.get('Content-Type', '').startswith('application/json') and response.text.strip():
            data = response.json()
        else:
            # Fallback: try to parse if body exists, otherwise treat as missing
            try:
                data = response.json()
            except Exception:
                text_preview = response.text[:200]
                print(f"Initial endpoint non-JSON or empty response (status {response.status_code}): {text_preview}")
                data = {}
        # Try common keys for session id; may be absent for this endpoint
        session_id = data.get("session") or data.get("sessionId") or data.get("session_id")
        print("Session ID:", session_id)

    except requests.exceptions.RequestException as e:
        print(f"Failed to fetch session ID: {e}")

    return session_id

def get_current_value(cookies_str, session_id, product_code, csrf_token=None):
    huf_value = "0"
    url = "https://b2bpartnerportal.com/occ/customer-service/api/list-price/list"
    payload = {
        "page": 0,
        "itemsPerPage": 10,
        "filter": {
            "lpProductCode": [product_code],
            "networkCode": ["MOLH_NETWRK"],
            "fcmsId": "330059510H",
        },
        "order": [
            {
                "columnCode": "companyCode",
                "direction": "ASC",
            },
        ],
    }

    headers = {
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Accept-Language": "en-US,en;q=0.9",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Content-Type": "application/json",
        "Cookie": cookies_str,
        "Host": "b2bpartnerportal.com",
        "Origin": "https://b2bpartnerportal.com",
        "Pragma": "no-cache",
        "Referer": "https://b2bpartnerportal.com/occ/#/customers/pricing-details/customer/2/1",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "X-Requested-With": "XMLHttpRequest",
        "X-User-Mode": "EXTERNAL_MODE",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
    }
    if session_id:
        headers["X-SESSION"] = f"{session_id}"
    if csrf_token:
        headers["X-CSRF-TOKEN"] = csrf_token
        headers["X-XSRF-TOKEN"] = csrf_token

    try:
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        status = response.status_code
        ctype = response.headers.get('Content-Type', '')
        preview = response.text[:200]
        response.raise_for_status()
        try:
            data = response.json()
        except ValueError:
            print(f"List price endpoint returned non-JSON (status {status}, type {ctype}): {preview}")
            return huf_value
        
        try:
            huf_value = data['content'][0]['lpAmount']['amount']
        except (KeyError, IndexError, TypeError):
            huf_value = "0"

    except requests.exceptions.RequestException as e:
        print(f"Failed to make POST request: {e}")
    
    return huf_value


def insert(evo100, evo95, evod, evodp):
    connection = None
    cursor = None
    try:
        connection = mysql.connector.connect(host=os.environ.get('DB_HOST'),
        user=os.environ.get('DB_USER'),
        passwd=os.environ.get('DB_PASSWORD'),
        db=os.environ.get('DB_NAME'))
        if connection.is_connected():
            cursor = connection.cursor()
            cursor.execute("insert into uzemanyag (EVO_100_benzin_plus, EVO_95_benzin, EVO_Diesel, EVO_Diesel_plus) values ('"+evo100+"','"+evo95+"','"+evod+"','"+evodp+"');")
            connection.commit()
    except Error as e:
        print("Error while connecting to MySQL", e)
    finally:
        # Close DB resources safely even when connect/cursor setup fails.
        if cursor is not None:
            cursor.close()
        if connection is not None and connection.is_connected():
            connection.close()

def check():
    try:
        # Prefer executing the request inside the browser so cookies/CSRF match the SPA exactly
        values = fetch_values_in_page(["GASOLINE", "PREMIUM_GASOLINE", "DIESEL", "PREMIUM_DIESEL"])
        gasoline_value = values.get("GASOLINE", "0")
        premium_gasoline_value = values.get("PREMIUM_GASOLINE", "0")
        diesel_value = values.get("DIESEL", "0")
        premium_diesel_value = values.get("PREMIUM_DIESEL", "0")

        insert(str(premium_gasoline_value)+" HUF",str(gasoline_value)+" HUF",str(diesel_value)+" HUF",str(premium_diesel_value)+" HUF")
    except Exception as e:
        print(f"check() failed: {e}")

