from flask import Flask, request, jsonify
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import requests
import time
import re
import os
from datetime import datetime, date
import pymysql

app = Flask(__name__)


# ====================== DB config ======================

DB_CONFIG = {
    "host": "127.0.0.1",
    "user": "root",
    "password": os.environ.get("DB_PASSWORD", ""),
    "database": "109mtcpro",
    "charset": "utf8mb4",
    "cursorclass": pymysql.cursors.DictCursor,
    "autocommit": True,
}

DB_TABLE = "109mtcpro"   # table name (same as db name in your dump)


def get_person_by_tc(tc: str):
    """Fetch a single person row by TC from MySQL/MariaDB."""
    conn = pymysql.connect(**DB_CONFIG)
    try:
        with conn.cursor() as cur:
            cur.execute(f"SELECT * FROM `{DB_TABLE}` WHERE TC = %s LIMIT 1", (tc,))
            return cur.fetchone()
    finally:
        conn.close()


# ====================== mail.tm helpers ======================

def create_temp_email():
    domains = requests.get("https://api.mail.tm/domains").json()
    domain = domains["hydra:member"][0]["domain"]

    username = f"user{int(time.time())}"
    email = f"{username}@{domain}"
    password = "TempPass123!"

    resp = requests.post("https://api.mail.tm/accounts", json={
        "address": email,
        "password": password
    })

    if resp.status_code not in [200, 201]:
        raise Exception(f"Failed to create email: {resp.text}")

    token_resp = requests.post("https://api.mail.tm/token", json={
        "address": email,
        "password": password
    })
    token = token_resp.json()["token"]

    return email, token


def wait_for_verification_code(token, timeout=70):
    headers = {"Authorization": f"Bearer {token}"}
    start = time.time()

    while time.time() - start < timeout:
        try:
            messages = requests.get("https://api.mail.tm/messages", headers=headers).json()
            for msg in messages.get("hydra:member", []):
                full = requests.get(f"https://api.mail.tm/messages/{msg['id']}", headers=headers).json()

                text_content = full.get("text") or ""
                html_content = full.get("html") or ""

                if isinstance(text_content, list):
                    text_content = " ".join(text_content)
                if isinstance(html_content, list):
                    html_content = " ".join(html_content)

                text = str(text_content) + " " + str(html_content)

                match = re.search(r"Do[ğg]rulama\s*Kodu\s*[:：]\s*([A-Za-z0-9]{10,20})", text, re.IGNORECASE)
                if match:
                    return match.group(1).strip()

                match2 = re.search(r"\b([A-Za-z0-9]{12,18})\b", text)
                if match2:
                    return match2.group(1).strip()

        except Exception as e:
            print("Mail check error:", e)

        time.sleep(3)

    raise Exception("Verification code not received in time")


# ====================== Selenium helpers ======================

def clear_and_type(element, text):
    element.click()
    time.sleep(0.25)
    element.send_keys(Keys.CONTROL + "a")
    element.send_keys(Keys.DELETE)
    time.sleep(0.15)
    element.send_keys(text)


def safe_get(driver, element_id):
    """Safely get value of an input"""
    try:
        el = driver.find_element(By.ID, element_id)
        return el.get_attribute("value") or None
    except:
        return None


def run_basvuru(tc, ad, soyad, dogum, cinsiyet):
    email, token = create_temp_email()
    print(f"[+] Temp email created: {email}")

    options = Options()
    options.add_argument("--start-maximized")
    # options.add_argument("--headless=new")
    options.add_argument("--disable-gpu")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")

    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
    wait = WebDriverWait(driver, 25)

    try:
        driver.get("https://ubs.bayburt.edu.tr//ogrenci/ogr0722/Default.aspx")
        time.sleep(2)

        # Select başvuru
        print("[1] Selecting başvuru type...")
        combo = wait.until(EC.element_to_be_clickable((By.ID, "cmbBasvuruAdi_Input")))
        combo.click()
        time.sleep(0.8)
        wait.until(EC.element_to_be_clickable(
            (By.XPATH, "//li[contains(text(),'Aftan Yararlanan')]")
        )).click()
        time.sleep(1.3)

        # İlk Giriş
        print("[2] Clicking İlk Giriş...")
        wait.until(EC.element_to_be_clickable((By.ID, "btnIlkGiris"))).click()
        time.sleep(3)

        # İleri
        print("[3] Clicking İleri...")
        wait.until(EC.element_to_be_clickable((By.ID, "btnTanimlarIleri"))).click()
        time.sleep(2.5)

        # Fill personal info
        print("[4] Filling personal info...")
        clear_and_type(wait.until(EC.element_to_be_clickable((By.ID, "txtTcKimlikNo_text"))), tc)
        clear_and_type(wait.until(EC.element_to_be_clickable((By.ID, "txtAdi_text"))), ad)
        clear_and_type(wait.until(EC.element_to_be_clickable((By.ID, "txtSoyadi_text"))), soyad)

        dogum_el = wait.until(EC.element_to_be_clickable((By.ID, "rdpDogumTarihi_dateInput_text")))
        clear_and_type(dogum_el, dogum)
        dogum_el.send_keys(Keys.TAB)
        time.sleep(0.5)

        cinsiyet_el = wait.until(EC.element_to_be_clickable((By.ID, "cmbCinsiyet_Input")))
        cinsiyet_el.click()
        time.sleep(0.7)
        if "erkek" in cinsiyet.lower():
            driver.find_element(By.XPATH, "//li[contains(text(),'Erkek')]").click()
        else:
            driver.find_element(By.XPATH, "//li[contains(text(),'Kadın')]").click()

        email_el = wait.until(EC.element_to_be_clickable((By.ID, "txtEMailAdresi_text")))
        driver.execute_script("arguments[0].removeAttribute('disabled')", email_el)
        clear_and_type(email_el, email)
        time.sleep(1)

        # Send code
        print("[5] Requesting verification code...")
        wait.until(EC.element_to_be_clickable((By.ID, "btnDogrulamaKoduGonder"))).click()
        time.sleep(3)

        # Wait for code
        print("[6] Waiting for email code...")
        code = wait_for_verification_code(token, timeout=70)
        print(f"[+] Code received: {code}")

        # Enter + verify code
        kod_el = wait.until(EC.element_to_be_clickable((By.ID, "txtDogrulamaKodu_text")))
        driver.execute_script("arguments[0].removeAttribute('disabled')", kod_el)
        clear_and_type(kod_el, code)

        wait.until(EC.element_to_be_clickable((By.ID, "btnDogrulamaKoduDogrula"))).click()
        print("[7] Code verified")
        time.sleep(2.5)

        # NVI
        print("[8] Clicking NVI'den Getir...")
        wait.until(EC.element_to_be_clickable((By.ID, "btnNVIdenGetir"))).click()
        time.sleep(3.5)

        # Manuel checkbox
        print("[9] Checking Manuel checkbox...")
        checkbox = wait.until(EC.presence_of_element_located((By.ID, "ChkYabanciMi")))
        if not checkbox.is_selected():
            driver.execute_script("arguments[0].click();", checkbox)
            time.sleep(3.5)

        # ========== Extract full NVI data ==========
        print("[10] Extracting identity data...")

        result = {
            "TC": safe_get(driver, "txtTcKimlikNo_text"),
            "ADI": safe_get(driver, "txtAdi_text"),
            "SOYADI": safe_get(driver, "txtSoyadi_text"),
            "CINSIYET": safe_get(driver, "cmbCinsiyet_Input") or cinsiyet,
            "DOGUMTARIHI": safe_get(driver, "rdpDogumTarihi_dateInput_text"),
            "DOGUMYERI": safe_get(driver, "txtDogumYeri_text"),
            "ANNEADI": safe_get(driver, "txtAnneAdi_text"),
            "BABAADI": safe_get(driver, "txtBabaAdi_text"),
            "SERINO": safe_get(driver, "txtSeriNo_text"),
            "CILTNO": safe_get(driver, "txtCiltNo_text"),
            "AILESIRANO": safe_get(driver, "txtAileSiraNo_text"),
            "SIRANO": safe_get(driver, "txtSiraNo_text"),
            "UYRUK": safe_get(driver, "cmbUyruk_Input"),
            "VERILISNEDENI": safe_get(driver, "txtCuzdaninVerilisNedeni_text"),
            "VERENMAKAM": safe_get(driver, "txtCuzdaninVerildigiYer_text"),
            "VERILISTARIHI": safe_get(driver, "rdpCuzdaninVerilisTarihi_dateInput_text"),
            "temp_email": email,
            "verification_code": code,
            "success": True
        }

        return result

    finally:
        driver.quit()


# ====================== Helpers ======================

def format_dogum(d):
    """Convert DB date to DD.MM.YYYY for the form."""
    if d is None:
        return None
    if isinstance(d, (datetime, date)):
        return d.strftime("%d.%m.%Y")
    # try string formats
    s = str(d).strip()
    for fmt in ("%Y-%m-%d", "%Y-%m-%d %H:%M:%S", "%d.%m.%Y", "%d/%m/%Y"):
        try:
            return datetime.strptime(s[:len(fmt) + 2] if " " in s else s, fmt).strftime("%d.%m.%Y")
        except ValueError:
            continue
    return s


def normalize_cinsiyet(c):
    c = (c or "").strip().lower()
    if c.startswith("kad") or "kad" in c or c == "k":
        return "Kadın"
    if c.startswith("erk") or "erk" in c or c == "e":
        return "Erkek"
    return "Erkek"


# ====================== Flask Routes ======================

@app.route("/sorgu", methods=["GET"])
def sorgu():
    """
    GET /sorgu?tc=11111111110
    Looks up TC in MySQL, then runs the full flow and returns the extracted NVI data.
    """
    tc = (request.args.get("tc") or "").strip()
    if not tc:
        return jsonify({"success": False, "error": "Missing query param: tc"}), 400

    # 1. DB lookup
    try:
        person = get_person_by_tc(tc)
    except Exception as e:
        return jsonify({"success": False, "error": f"DB error: {e}"}), 500

    if not person:
        return jsonify({"success": False, "error": f"TC {tc} not found"}), 404

    # 2. Prepare fields for the form
    ad       = (person.get("AD") or "").strip()
    soyad    = (person.get("SOYAD") or "").strip()
    dogum    = format_dogum(person.get("DOGUMTARIHI"))
    cinsiyet = normalize_cinsiyet(person.get("CINSIYET"))

    if not (ad and soyad and dogum):
        return jsonify({
            "success": False,
            "error": "Incomplete record in DB",
            "record": {k: str(v) for k, v in person.items()}
        }), 422

    # 3. Run the browser flow
    try:
        result = run_basvuru(tc=tc, ad=ad, soyad=soyad, dogum=dogum, cinsiyet=cinsiyet)
        # also include the DB row for reference
        result["db_row"] = {k: (str(v) if v is not None else None) for k, v in person.items()}
        return jsonify(result)
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


@app.route("/basvuru", methods=["POST"])
def basvuru():
    """Kept for backward compatibility / manual use."""
    data = request.json or {}

    required = ["tc", "ad", "soyad", "dogum", "cinsiyet"]
    missing = [f for f in required if not data.get(f)]
    if missing:
        return jsonify({"success": False, "error": f"Missing fields: {missing}"}), 400

    try:
        result = run_basvuru(
            tc=data["tc"].strip(),
            ad=data["ad"].strip(),
            soyad=data["soyad"].strip(),
            dogum=data["dogum"].strip(),
            cinsiyet=data["cinsiyet"].strip()
        )
        return jsonify(result)
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


@app.route("/")
def index():
    return jsonify({
        "message": "Yatay Geçiş NVI API",
        "endpoints": {
            "GET /sorgu?tc=11111111110": "Lookup TC in DB, run flow, return NVI data",
            "POST /basvuru": "Manual (tc, ad, soyad, dogum, cinsiyet in JSON body)"
        }
    })


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)