#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SAGA WEB - JURNAL BANCA - SCRIPT UNIFICAT (PAS 1 + PAS 2)
==========================================================
Combina cele doua scripturi anterioare intr-o singura sesiune de browser:

  PAS 1 (read-only):
    - Citeste toate zilele din Sectiunea 1
    - Citeste toate tranzactiile din Sectiunea 2
    - Identifica tranzactiile care necesita reconciliere
      (cont_d incepe cu 401 = plata furnizor, cont_c incepe cu 411 = incasare client)
    - Salveaza raport CSV ca backup: jurnal_banca_de_reconciliat.csv

  PROMPT:
    - Te intreaba ce sa faca mai departe:
        D = DRY_RUN  (simuleaza reconcilierea, NU salveaza in SAGA)
        L = LIVE     (salveaza modificarile real in SAGA)
        N = NU       (iesire, ai doar CSV-ul)

  PAS 2 (daca alegi D sau L):
    - Pentru fiecare tranzactie de reconciliat:
        1. Selecteaza ziua in Sectiunea 1
        2. Gaseste si selecteaza tranzactia in Sectiunea 2
        3. Apasa Modific
        4. Asteapta facturile in Sectiunea 3
        5. Aplica logica FIFO (cea mai veche factura intai)
        6. Apasa Salvez (sau Renunt in DRY_RUN)
    - Actualizeaza CSV-ul cu statusul fiecarei tranzactii
"""

import time
import sys
import csv
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import configparser


# ============================================================================
# CONFIGURARE
# ============================================================================
CSV_FILE = "jurnal_banca_de_reconciliat.csv"

# Perioada — modifica aici cand schimbi luna
DATA_START = "01.03.2026"   # zi de inceput (inclusiv)
DATA_END   = "31.03.2026"   # zi de final  (inclusiv)


# ============================================================================
# CULORI CONSOLA
# ============================================================================
class C:
    GREEN   = '\033[92m'
    RED     = '\033[91m'
    YELLOW  = '\033[93m'
    BLUE    = '\033[94m'
    CYAN    = '\033[96m'
    MAGENTA = '\033[95m'
    RESET   = '\033[0m'
    BOLD    = '\033[1m'

def log(text, color=C.RESET):
    print(f"{color}{text}{C.RESET}")


# ============================================================================
# FUNCTII UTILITARE
# ============================================================================

def parse_amount(text):
    """Converteste '100 000.00' sau '516.00' in float."""
    if not text or not str(text).strip():
        return 0.0
    cleaned = str(text).strip().replace('\xa0', '').replace(' ', '').replace(',', '.')
    try:
        return float(cleaned)
    except ValueError:
        return 0.0


def parse_date_ro(text):
    """'01.03.2026' => datetime"""
    try:
        return datetime.strptime(text.strip(), "%d.%m.%Y")
    except Exception:
        return datetime.max


# ============================================================================
# SELECTIE FIRMA - BONO FINSTART S.R.L.
# ============================================================================

def select_bono_finstart(driver, wait):
    """Selecteaza firma BONO FINSTART S.R.L. din lista de firme inainte de Conectare.
    Foloseste translate() pentru a fi robust la 'S.R.L.' vs 'SRL'."""
    try:
        bono_row = wait.until(EC.element_to_be_clickable((
            By.XPATH,
            "//div[contains(@class, 'rowSelectable')]"
            "[.//span[contains(@class, 'firmaNume') and "
            "contains(translate(normalize-space(.), '.', ''), 'BONO FINSTART')]]"
        )))
        driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", bono_row)
        time.sleep(0.3)
        try:
            bono_row.click()
        except Exception:
            driver.execute_script("arguments[0].click();", bono_row)
        time.sleep(0.5)
        log("   OK BONO FINSTART S.R.L. selectat", C.GREEN)
        return True
    except Exception:
        try:
            bono_span = wait.until(EC.element_to_be_clickable((
                By.XPATH,
                "//span[contains(@class, 'firmaNume') and "
                "contains(translate(normalize-space(.), '.', ''), 'BONO FINSTART')]"
            )))
            driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", bono_span)
            time.sleep(0.3)
            driver.execute_script("arguments[0].click();", bono_span)
            time.sleep(0.5)
            log("   OK BONO FINSTART S.R.L. selectat (fallback)", C.GREEN)
            return True
        except Exception as e2:
            log(f"   ATENTIE: nu s-a putut selecta BONO FINSTART S.R.L.: {e2}", C.YELLOW)
            return False


# ============================================================================
# SECTIUNEA 1 - Zile
# ============================================================================

def get_section1_rows(driver):
    """Toate randurile din Sectiunea 1 (zilele extrasului de cont), cu sume."""
    rows = driver.find_elements(By.CSS_SELECTOR, "tr.rowSelectable_Solduri")
    result = []
    for row in rows:
        try:
            data     = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Data").text.strip()
            incasari = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Incasari").text.strip()
            plati    = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Plati").text.strip()
            try:
                pk = row.find_element(By.CSS_SELECTOR, "input.rowFieldInput_PK").get_attribute("value")
            except Exception:
                pk = ""
            if data:
                result.append({
                    'element':  row,
                    'data':     data,
                    'incasari': parse_amount(incasari),
                    'plati':    parse_amount(plati),
                    'pk':       pk,
                })
        except Exception:
            continue
    return result


def click_day(driver, data_str):
    """Cauta si apasa pe ziua cu data_str in Sectiunea 1."""
    rows = get_section1_rows(driver)
    for row in rows:
        if row['data'] == data_str:
            try:
                row['element'].click()
            except Exception:
                driver.execute_script("arguments[0].click();", row['element'])
            time.sleep(1.5)
            return True
    return False


# ============================================================================
# SECTIUNEA 2 - Tranzactii
# ============================================================================

def get_section2_rows(driver):
    """Toate randurile din Sectiunea 2 (tranzactiile zilei selectate)."""
    rows = driver.find_elements(By.CSS_SELECTOR, "tr.rowSelectable_Casa")
    result = []
    for row in rows:
        try:
            nr_doc     = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_NrDoc").text.strip()
            cont_d     = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Cont_D").text.strip()
            cont_c     = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Cont_C").text.strip()
            suma       = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Suma").text.strip()
            explicatie = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Explicatie").text.strip()
            try:
                id_nota = row.find_element(By.CSS_SELECTOR, "input.rowFieldInput_IdNota").get_attribute("value")
            except Exception:
                id_nota = ""
            if nr_doc:
                result.append({
                    'element':    row,
                    'nr_doc':     nr_doc,
                    'cont_d':     cont_d,
                    'cont_c':     cont_c,
                    'suma':       parse_amount(suma),
                    'explicatie': explicatie,
                    'id_nota':    id_nota,
                })
        except Exception:
            continue
    return result


def find_section2_row(driver, id_nota, nr_doc=None):
    """Gaseste randul din Sectiunea 2 dupa id_nota (sau fallback dupa nr_doc)."""
    try:
        row = driver.find_element(
            By.XPATH,
            f"//tr[contains(@class,'rowSelectable_Casa')]"
            f"[.//input[contains(@class,'rowFieldInput_IdNota')][@value='{id_nota}']]"
        )
        return row
    except Exception:
        pass

    if nr_doc:
        try:
            rows = driver.find_elements(By.CSS_SELECTOR, "tr.rowSelectable_Casa")
            for row in rows:
                try:
                    nd = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_NrDoc").text.strip()
                    if nd == str(nr_doc):
                        return row
                except Exception:
                    continue
        except Exception:
            pass
    return None


import re

def is_red_color(color_str):
    """SAGA marcheaza cu ROSU randurile care necesita reconciliere."""
    if not color_str:
        return False
    m = re.match(r'rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)', color_str)
    if not m:
        return False
    r, g, b = int(m.group(1)), int(m.group(2)), int(m.group(3))
    return r > 120 and g < 100 and b < 100


def get_cell_color(row_elem, css_class):
    """Culoarea textului unei celule din rand (string CSS color)."""
    try:
        span = row_elem.find_element(By.CSS_SELECTOR, "span." + css_class)
        return span.value_of_css_property('color')
    except Exception:
        return ''


def classify_transaction(t):
    """Decide daca tranzactia necesita reconciliere — DUPA CULOARE.

    SAGA marcheaza cu rosu cellele care apartin unor randuri ce trebuie
    reconciliate cu facturi. Daca ambele celule (Cont D si Cont C) sunt
    negre, tranzactia nu necesita reconciliere (skip).
    """
    cont_d = t['cont_d']
    cont_c = t['cont_c']
    row    = t.get('element')

    if row is None:
        # Fallback la logica veche
        if cont_d.startswith('401'):
            return True, 'PLATA_FURNIZOR', cont_d
        if cont_c.startswith('411'):
            return True, 'INCASARE_CLIENT', cont_c
        return False, 'SKIP', ''

    d_red = is_red_color(get_cell_color(row, 'rowFieldText_Cont_D'))
    c_red = is_red_color(get_cell_color(row, 'rowFieldText_Cont_C'))

    if not (d_red or c_red):
        return False, 'SKIP', ''

    if cont_d.startswith('401'):
        return True, 'PLATA_FURNIZOR', cont_d
    if cont_c.startswith('411'):
        return True, 'INCASARE_CLIENT', cont_c
    return True, 'NESTANDARD_ROSU', f"Dr:{cont_d}/Cr:{cont_c}"


# ============================================================================
# BUTOANE TOOLBAR SECTIUNEA 2
# ============================================================================

def click_modific(driver, wait):
    """Apasa butonul Modific din toolbar-ul Sectiunii 2."""
    selectori = [
        (By.CSS_SELECTOR, "button.buttonOperationEdit_Casa"),
        (By.XPATH, "//button[contains(@class,'buttonOperationEdit_Casa')]"),
        (By.XPATH, "//button[contains(@class,'buttonOperation') and contains(@class,'Edit') and contains(@class,'Casa')]"),
    ]
    for by, sel in selectori:
        try:
            btn = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((by, sel)))
            btn.click()
            log("   OK buton Modific apasat", C.GREEN)
            return True
        except Exception:
            continue
    log("   EROARE: nu am gasit butonul Modific", C.RED)
    return False


def click_salvez(driver, wait):
    """Apasa butonul Salvez din toolbar-ul Sectiunii 2.
    Incearca: click direct, click via JS, apoi shortcut ALT+S (tooltip oficial).
    """
    selectori = [
        (By.CSS_SELECTOR, "button.buttonOperationSave_Casa"),
        (By.XPATH, "//button[contains(@class,'buttonOperationSave_Casa')]"),
        (By.XPATH, "//button[contains(@class,'buttonOperation') and contains(@class,'Save') and contains(@class,'Casa')]"),
    ]
    # Metoda 1+2: click standard / click via JS
    for by, sel in selectori:
        try:
            btn = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((by, sel)))
            try:
                btn.click()
            except Exception:
                driver.execute_script("arguments[0].click();", btn)
            log("   OK buton Salvez apasat", C.GREEN)
            return True
        except Exception:
            continue

    # Metoda 3: shortcut ALT+S (din tooltip-ul SAGA "Salvare (ALT + S)")
    try:
        from selenium.webdriver.common.keys import Keys
        body = driver.find_element(By.TAG_NAME, "body")
        body.send_keys(Keys.ALT + 's')
        time.sleep(1)
        log("   OK buton Salvez apasat (ALT+S shortcut)", C.GREEN)
        return True
    except Exception as e:
        log(f"   EROARE: nu am gasit butonul Salvez si ALT+S a esuat: {e}", C.RED)
        return False


def click_renunt(driver):
    """Apasa butonul Renunt (anulare modificare)."""
    selectori = [
        (By.CSS_SELECTOR, "button.buttonOperationCancel_Casa"),
        (By.XPATH, "//button[contains(@class,'buttonOperationCancel_Casa')]"),
        (By.XPATH, "//button[contains(@class,'buttonOperation') and contains(@class,'Cancel') and contains(@class,'Casa')]"),
    ]
    for by, sel in selectori:
        try:
            btn = WebDriverWait(driver, 3).until(EC.element_to_be_clickable((by, sel)))
            btn.click()
            time.sleep(1)
            return True
        except Exception:
            continue
    return False


def wait_for_view_mode(driver, timeout=15):
    """Asteapta pana butonul Modific reapare (semn ca s-a salvat cu succes)."""
    try:
        WebDriverWait(driver, timeout).until(
            EC.any_of(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button.buttonOperationEdit_Casa")),
                EC.element_to_be_clickable((By.XPATH, "//button[contains(@class,'buttonOperationEdit_Casa')]")),
            )
        )
        return True
    except Exception:
        return False


# ============================================================================
# SECTIUNEA 3 - Facturi (CasaDetalii)
# ============================================================================

def wait_section3_loaded(driver, timeout=15):
    """Asteapta pana Sectiunea 3 are cel putin un rand cu factura."""
    try:
        WebDriverWait(driver, timeout).until(lambda d: len([
            r for r in d.find_elements(
                By.CSS_SELECTOR, "#tableMain_CasaDetalii tr.rowSelectable_CasaDetalii"
            )
            if 'exampleRow_CasaDetalii' not in (r.get_attribute('class') or '')
            and r.is_displayed()
        ]) > 0)
        return True
    except Exception:
        return False


def get_section3_rows(driver):
    """Toate randurile cu facturi din Sectiunea 3."""
    all_rows = driver.find_elements(
        By.CSS_SELECTOR, "#tableMain_CasaDetalii tr.rowSelectable_CasaDetalii"
    )
    result = []
    for row in all_rows:
        clase = row.get_attribute('class') or ''
        if 'exampleRow_CasaDetalii' in clase:
            continue
        if not row.is_displayed():
            continue
        try:
            nr_factura = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_NrFactura").text.strip()
            data_fact  = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Data").text.strip()
            neachitat  = row.find_element(By.CSS_SELECTOR, "span.rowFieldText_Neachitat").text.strip()
            try:
                neachitat_real = row.find_element(
                    By.CSS_SELECTOR, "input.rowFieldInput_NeachitatReal"
                ).get_attribute("value")
            except Exception:
                neachitat_real = neachitat

            if nr_factura:
                result.append({
                    'element':        row,
                    'nr_factura':     nr_factura,
                    'data_fact':      data_fact,
                    'data_parsed':    parse_date_ro(data_fact),
                    'neachitat':      parse_amount(neachitat),
                    'neachitat_real': parse_amount(neachitat_real),
                })
        except Exception:
            continue
    return result


# ============================================================================
# LOGICA FIFO
# ============================================================================

def bifa_integral(driver, row_elem, nr_factura):
    """Bifează checkbox-ul Integral pe randul facturii.
    Incearca 3 metode pana cand una functioneaza:
      1. Click pe label (cel mai natural, simuleaza userul)
      2. Click direct pe input via JS
      3. Setare checked=true + events via JS
    """
    # Scroll la rand pentru a fi sigur ca e vizibil/interactionabil
    try:
        driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", row_elem)
        time.sleep(0.3)
    except Exception:
        pass

    # Selectam checkbox-ul si label-ul aferent
    try:
        checkbox = row_elem.find_element(
            By.CSS_SELECTOR, "input.rowFieldInput_Integral"
        )
    except Exception as e:
        log(f"     EROARE: nu am gasit checkbox-ul Integral: {e}", C.RED)
        return False

    if checkbox.is_selected():
        log(f"     INFO: {nr_factura} era deja bifata", C.CYAN)
        return True

    # Metoda 1: click pe label (cel mai fiabil pentru bife custom CSS)
    try:
        label = row_elem.find_element(
            By.XPATH, ".//label[.//input[contains(@class,'rowFieldInput_Integral')]]"
        )
        driver.execute_script("arguments[0].click();", label)
        time.sleep(0.5)
        if checkbox.is_selected():
            log(f"     OK bifa Integral aplicata (label click)", C.GREEN)
            return True
    except Exception:
        pass

    # Metoda 2: click direct pe input via JS
    try:
        driver.execute_script("arguments[0].click();", checkbox)
        time.sleep(0.5)
        if checkbox.is_selected():
            log(f"     OK bifa Integral aplicata (input click)", C.GREEN)
            return True
    except Exception:
        pass

    # Metoda 3: forteaza checked + events
    try:
        driver.execute_script("""
            arguments[0].checked = true;
            arguments[0].dispatchEvent(new Event('input',  {bubbles: true}));
            arguments[0].dispatchEvent(new Event('change', {bubbles: true}));
            arguments[0].dispatchEvent(new Event('click',  {bubbles: true}));
        """, checkbox)
        time.sleep(0.5)
        if checkbox.is_selected():
            log(f"     OK bifa Integral aplicata (force JS)", C.GREEN)
            return True
    except Exception as e:
        log(f"     EROARE force JS: {e}", C.RED)

    log(f"     EROARE: nu am putut bifa Integral pentru {nr_factura}", C.RED)
    return False


def completeaza_achitat(driver, row_elem, suma, nr_factura):
    """Completeaza suma in campul Achitat pe randul facturii."""
    try:
        driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", row_elem)
        time.sleep(0.3)
    except Exception:
        pass

    try:
        achitat_input = row_elem.find_element(
            By.CSS_SELECTOR, "input.rowFieldInput_Achitat"
        )
    except Exception as e:
        log(f"     EROARE: nu am gasit campul Achitat: {e}", C.RED)
        return False

    try:
        try:
            achitat_input.click()
        except Exception:
            driver.execute_script("arguments[0].focus();", achitat_input)
        time.sleep(0.3)
        achitat_input.clear()
        time.sleep(0.2)
        achitat_input.send_keys(f"{suma:.2f}")
        time.sleep(0.3)
        driver.execute_script("""
            arguments[0].dispatchEvent(new Event('input',  {bubbles: true}));
            arguments[0].dispatchEvent(new Event('change', {bubbles: true}));
            arguments[0].dispatchEvent(new Event('blur',   {bubbles: true}));
        """, achitat_input)
        time.sleep(0.5)
        log(f"     OK suma {suma:.2f} completata in Achitat ({nr_factura})", C.GREEN)
        return True
    except Exception as e:
        log(f"     EROARE completare Achitat: {e}", C.RED)
        return False


def apply_fifo_matching(driver, section3_rows, suma_plata, dry_run=True):
    """Aplica logica FIFO: sorteaza facturile dupa data, marcheaza de la cea mai veche.

    IMPORTANT: UI-ul SE MODIFICA in AMBELE moduri (DRY_RUN si LIVE) ca sa poti
    verifica vizual ce face scriptul. Diferenta apare doar la final:
      - DRY_RUN: caller-ul apasa Renunt (modificarile sunt aruncate)
      - LIVE:    caller-ul apasa Salvez (modificarile sunt persistate)
    """
    if not section3_rows:
        return False, 0.0, ["Nu exista facturi in Sectiunea 3"]

    sorted_rows = sorted(section3_rows, key=lambda r: r['data_parsed'])

    remaining = suma_plata
    total_neachitat = sum(r['neachitat_real'] for r in sorted_rows)
    detalii = []

    log(f"   Total de plata:     {suma_plata:.2f} RON", C.CYAN)
    log(f"   Total neachitat:    {total_neachitat:.2f} RON ({len(sorted_rows)} facturi)", C.CYAN)

    if total_neachitat == 0:
        return False, 0.0, ["Toate facturile sunt deja achitate"]

    for factura in sorted_rows:
        if remaining <= 0:
            log(f"   SKIP {factura['nr_factura']} (suma epuizata)", C.RESET)
            detalii.append(f"SKIP {factura['nr_factura']}")
            continue

        neachitat = factura['neachitat_real']

        if neachitat <= 0:
            log(f"   SKIP {factura['nr_factura']} (deja achitata)", C.RESET)
            detalii.append(f"SKIP {factura['nr_factura']} (achitata)")
            continue

        row_elem = factura['element']

        if neachitat <= remaining:
            # ---- Plata TOTALA: bifam Integral ----
            action = f"Integral  {factura['nr_factura']} ({neachitat:.2f} RON)"
            log(f"   CHECK INTEGRAL: {factura['nr_factura']} | {factura['data_fact']} | {neachitat:.2f} RON", C.GREEN)
            detalii.append(action)

            # Se face MEREU (si in DRY_RUN, si in LIVE) - vezi docstring
            bifa_integral(driver, row_elem, factura['nr_factura'])
            remaining -= neachitat

        else:
            # ---- Plata PARTIALA: completam suma in campul Achitat ----
            action = f"Partial   {factura['nr_factura']} ({remaining:.2f} din {neachitat:.2f} RON)"
            log(f"   ACHITAT PARTIAL: {factura['nr_factura']} | {factura['data_fact']} | {remaining:.2f} RON (din {neachitat:.2f})", C.YELLOW)
            detalii.append(action)

            # Se face MEREU (si in DRY_RUN, si in LIVE)
            completeaza_achitat(driver, row_elem, remaining, factura['nr_factura'])
            remaining = 0

    if abs(remaining) > 0.01:
        log(f"   ATENTIE: suma ramasa neaplicata: {remaining:.2f} RON", C.YELLOW)
        detalii.append(f"Suma ramasa: {remaining:.2f} RON")

    suma_procesata = suma_plata - max(remaining, 0)
    return True, suma_procesata, detalii


# ============================================================================
# PROMPT UTILIZATOR
# ============================================================================

def cere_decizie_utilizator(nr_tranzactii):
    """Cere utilizatorului sa decida ce facem mai departe dupa PAS 1.
    Returneaza:
      'DRY_RUN' - simulam reconcilierea fara salvare
      'LIVE'    - salveaza modificarile in SAGA
      'NU'      - iesim, doar CSV
    """
    log("\n" + "=" * 70, C.MAGENTA)
    log(f"Am gasit {nr_tranzactii} tranzactii de reconciliat.", C.BOLD)
    log("=" * 70, C.MAGENTA)
    log("Ce vrei sa fac mai departe?", C.BOLD)
    log("  [D] DRY_RUN - Simulez reconcilierea, NU salvez nimic in SAGA (recomandat prima data)", C.YELLOW)
    log("  [L] LIVE    - Salvez modificarile REAL in SAGA", C.RED)
    log("  [N] NU      - Ies acum, am doar CSV-ul cu ce-ar fi de facut", C.CYAN)
    log("", C.RESET)

    while True:
        try:
            raspuns = input("Alegere (D / L / N): ").strip().upper()
        except (EOFError, KeyboardInterrupt):
            return 'NU'
        if raspuns in ('D', 'DRY_RUN', 'DRY'):
            return 'DRY_RUN'
        if raspuns in ('L', 'LIVE'):
            log("  ATENTIE: ai ales LIVE — modificarile se vor salva in SAGA!", C.RED)
            try:
                conf = input("  Confirma cu YES pentru a continua: ").strip().upper()
            except (EOFError, KeyboardInterrupt):
                return 'NU'
            if conf == 'YES':
                return 'LIVE'
            log("  Anulat. Reincearca.", C.YELLOW)
            continue
        if raspuns in ('N', 'NU', 'NO'):
            return 'NU'
        log("  Raspuns invalid. Foloseste D, L sau N.", C.RED)


# ============================================================================
# MAIN
# ============================================================================

print("\n" + "=" * 70)
log("SAGA WEB - JURNAL BANCA - SCRIPT UNIFICAT (PAS 1 + PAS 2)", C.BOLD)
log("PAS 1: scanare (read-only)  =>  prompt  =>  PAS 2: reconciliere (optional)", C.YELLOW)
print("=" * 70 + "\n")

driver = None
try:
    # ------------------------------------------------------------------
    # 1. Conectare la Chrome existent (lansat de RUN_LOGIN.bat)
    # ------------------------------------------------------------------
    log("1. Conectare la Chrome existent (port 9222)...", C.BLUE)
    options = Options()
    options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
    try:
        driver = webdriver.Chrome(options=options)
    except Exception as e:
        log("\nEROARE: Nu pot conecta la Chrome pe port 9222.", C.RED)
        log("   Ruleaza mai intai RUN_LOGIN.bat si lasa browser-ul deschis.", C.YELLOW)
        log(f"   Detalii: {str(e)}", C.RED)
        sys.exit(1)
    wait = WebDriverWait(driver, 60)
    log("   OK conectat la Chrome (sesiunea de la login)", C.GREEN)

    # ------------------------------------------------------------------
    # 4. Navigare la Jurnal de Banca
    # ------------------------------------------------------------------
    log("\n4. Navighez la Jurnal de Banca...", C.BLUE)
    wait.until(EC.element_to_be_clickable((By.ID, "navbar_Operatii"))).click()
    time.sleep(1)
    wait.until(EC.element_to_be_clickable((By.ID, "navbar_JurnalDeBanca"))).click()
    time.sleep(3)
    log("   OK pe pagina Jurnal de Banca", C.GREEN)

    # ------------------------------------------------------------------
    # 4.5. MODIFICARE PERIOADA (folosim DATA_START / DATA_END din config)
    # ------------------------------------------------------------------
    log("\n" + "="*70, C.BLUE)
    log(f"MODIFICARE PERIOADA - {DATA_START} - {DATA_END}", C.BLUE)
    log("="*70, C.BLUE)

    log("\nClick pe Interval...", C.BLUE)
    interval_button = wait.until(EC.element_to_be_clickable((By.ID, "navbar_Interval")))
    interval_button.click()
    time.sleep(1)
    log("   OK meniu Interval deschis", C.GREEN)

    log(f"\nCompletez data inceput ({DATA_START})...", C.BLUE)
    interval_start = wait.until(EC.presence_of_element_located((By.ID, "navbar_IntervalStart")))
    interval_start.click()
    time.sleep(0.5)
    interval_start.send_keys(Keys.CONTROL + "a")
    time.sleep(0.2)
    interval_start.send_keys(DATA_START)
    time.sleep(0.5)
    log(f"   OK data inceput: {DATA_START}", C.GREEN)

    log(f"\nCompletez data final ({DATA_END})...", C.BLUE)
    time.sleep(1)
    interval_end = wait.until(EC.presence_of_element_located((By.ID, "navbar_IntervalEnd")))
    interval_end.click()
    time.sleep(0.5)
    interval_end.send_keys(Keys.CONTROL + "a")
    time.sleep(0.2)
    interval_end.send_keys(DATA_END)
    time.sleep(0.5)
    interval_end.send_keys(Keys.TAB)
    time.sleep(1)
    log(f"   OK data final: {DATA_END}", C.GREEN)

    log("\nInchid dropdown cu Escape...", C.BLUE)
    time.sleep(0.5)
    driver.find_element(By.TAG_NAME, "body").send_keys(Keys.ESCAPE)
    time.sleep(1)
    log("   OK dropdown inchis", C.GREEN)

    log("\nAstept aplicarea perioadei...", C.BLUE)
    time.sleep(2)
    log("   OK perioada aplicata", C.GREEN)

    # ==================================================================
    # ===== PAS 1: SCANARE TRANZACTII =====
    # ==================================================================
    log("\n" + "=" * 70, C.CYAN)
    log("PAS 1: SCANARE TRANZACTII (read-only)", C.BOLD)
    log("=" * 70, C.CYAN)

    log("\n5. Citesc zilele din Sectiunea 1...", C.BLUE)
    toate_zilele = get_section1_rows(driver)
    log(f"   Total randuri gasite: {len(toate_zilele)}", C.CYAN)

    # SAGA aduce uneori toate zilele, nu doar cele din perioada selectata.
    # De aceea filtram explicit aici dupa DATA_START / DATA_END.
    data_start_dt = parse_date_ro(DATA_START)
    data_end_dt   = parse_date_ro(DATA_END)

    zile_active     = []
    zile_in_afara   = 0
    zile_fara_misc  = 0
    for z in toate_zilele:
        if z['incasari'] <= 0 and z['plati'] <= 0:
            zile_fara_misc += 1
            continue
        z_date = parse_date_ro(z['data'])
        if z_date < data_start_dt or z_date > data_end_dt:
            zile_in_afara += 1
            continue
        zile_active.append(z)

    log(f"   Zile fara miscari (ignorate):           {zile_fara_misc}", C.CYAN)
    log(f"   Zile cu miscari in afara perioadei:     {zile_in_afara}", C.YELLOW)
    log(f"   Zile RETINUTE ({DATA_START} - {DATA_END}): {len(zile_active)}", C.GREEN)
    log("", C.RESET)
    for z in zile_active:
        log(f"     {z['data']}  |  Incasari: {z['incasari']:>12.2f}  |  Plati: {z['plati']:>12.2f}", C.YELLOW)

    log("\n6. Scanez tranzactiile...", C.BLUE)
    log("-" * 70, C.RESET)

    de_reconciliat   = []
    total_tranzactii = 0

    for zi in zile_active:
        log(f"\n  Zi: {zi['data']}", C.CYAN)
        try:
            zi['element'].click()
            time.sleep(1.5)
        except Exception as e:
            log(f"    EROARE la click pe zi: {e}", C.RED)
            continue

        tranzactii = get_section2_rows(driver)
        total_tranzactii += len(tranzactii)
        log(f"  Tranzactii gasite: {len(tranzactii)}", C.BLUE)

        for t in tranzactii:
            necesita, tip, cont_partener = classify_transaction(t)
            marker = ">>>" if necesita else "   "
            color  = C.GREEN if necesita else C.RESET
            log(
                f"  {marker} Nr.{t['nr_doc']:>3s}  "
                f"Dr:{t['cont_d']:<12s} Cr:{t['cont_c']:<12s}  "
                f"Suma:{t['suma']:>12.2f}  "
                f"[{tip:<18s}]  "
                f"{t['explicatie'][:35]}",
                color
            )

            if necesita:
                de_reconciliat.append({
                    'data':           zi['data'],
                    'nr_doc':         t['nr_doc'],
                    'cont_d':         t['cont_d'],
                    'cont_c':         t['cont_c'],
                    'suma':           t['suma'],
                    'tip':            tip,
                    'cont_partener':  cont_partener,
                    'explicatie':     t['explicatie'],
                    'id_nota':        t['id_nota'],
                    'pk_zi':          zi['pk'],
                    'reconciliat':    'NU',
                })

    # 7. Salvez CSV ca backup
    log("\n7. Salvez raport CSV (backup)...", C.BLUE)
    fieldnames = [
        'data', 'nr_doc', 'cont_d', 'cont_c', 'suma',
        'tip', 'cont_partener', 'explicatie',
        'id_nota', 'pk_zi', 'reconciliat'
    ]
    with open(CSV_FILE, 'w', newline='', encoding='utf-8-sig') as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=';')
        writer.writeheader()
        writer.writerows(de_reconciliat)
    log(f"   OK salvat: {CSV_FILE}", C.GREEN)

    # 8. Sumar PAS 1
    plati_furn  = [t for t in de_reconciliat if t['tip'] == 'PLATA_FURNIZOR']
    incasari_cl = [t for t in de_reconciliat if t['tip'] == 'INCASARE_CLIENT']

    log("\n" + "=" * 70, C.BLUE)
    log("SUMAR PAS 1 (SCANARE):", C.BOLD)
    log(f"  Zile scanate:                  {len(zile_active)}", C.CYAN)
    log(f"  Total tranzactii vazute:       {total_tranzactii}", C.CYAN)
    log(f"  De reconciliat (total):        {len(de_reconciliat)}", C.GREEN)
    log(f"    - Plati furnizor  (Dr 401):  {len(plati_furn)}", C.YELLOW)
    log(f"    - Incasari client (Cr 411):  {len(incasari_cl)}", C.YELLOW)
    log(f"  Backup CSV: {CSV_FILE}", C.GREEN)
    log("=" * 70, C.BLUE)

    # ==================================================================
    # ===== PROMPT UTILIZATOR =====
    # ==================================================================
    if not de_reconciliat:
        log("\nNu exista tranzactii de reconciliat. Ies.", C.YELLOW)
        input("\nApasa Enter pentru a inchide browser...")
        driver.quit()
        sys.exit(0)

    # Setare automata - fara prompt. Schimba aici comportamentul:
    #   DRY_RUN = True  -> bifeaza/completeaza UI, dar la final apasa Renunt (NU salveaza)
    #   DRY_RUN = False -> bifeaza/completeaza UI si apasa Salvez (SALVEAZA in SAGA)
    DRY_RUN = False
    if DRY_RUN:
        log(f"\n>>> Trec automat pe DRY_RUN (simulare). {len(de_reconciliat)} tranzactii de procesat.", C.YELLOW)
    else:
        log(f"\n>>> Trec automat pe LIVE (salvare reala). {len(de_reconciliat)} tranzactii de procesat.", C.RED + C.BOLD)

    # ==================================================================
    # ===== PAS 2: RECONCILIERE FACTURI =====
    # ==================================================================
    log("\n" + "=" * 70, C.MAGENTA)
    log("PAS 2: RECONCILIERE FACTURI", C.BOLD)
    if DRY_RUN:
        log("MODUL: DRY RUN", C.YELLOW)
        log("  - UI-ul SE va modifica (vezi bifare/completare pe ecran)", C.YELLOW)
        log("  - dar la final se apasa Renunt, deci NIMIC nu se salveaza in SAGA", C.YELLOW)
    else:
        log("MODUL: LIVE - se salveaza modificarile in SAGA!", C.RED + C.BOLD)
    log("=" * 70, C.MAGENTA)

    log("\n9. Incep reconcilierea...", C.BLUE)
    log("-" * 70, C.RESET)

    rezultate    = []
    ziua_curenta = None
    de_procesat  = de_reconciliat   # toate tranzactiile scanate au reconciliat='NU'

    for idx, tranz in enumerate(de_procesat, 1):
        data       = tranz['data']
        nr_doc     = tranz['nr_doc']
        id_nota    = tranz['id_nota']
        suma       = parse_amount(tranz['suma'])
        tip        = tranz['tip']
        explicatie = tranz['explicatie'][:40]

        log(f"\n[{idx}/{len(de_procesat)}] {data} | Nr.{nr_doc} | {suma:.2f} RON | {tip}", C.MAGENTA)
        log(f"  Explicatie: {explicatie}", C.RESET)

        status_final  = 'EROARE'
        detalii_final = []

        try:
            # 9a. Click pe zi daca s-a schimbat
            if data != ziua_curenta:
                log(f"  Selectez ziua {data} in Sectiunea 1...", C.BLUE)
                ok = click_day(driver, data)
                if not ok:
                    log(f"  EROARE: ziua {data} nu a fost gasita in Sectiunea 1", C.RED)
                    status_final = 'EROARE_ZI'
                    rezultate.append({**tranz, 'reconciliat': status_final})
                    continue
                ziua_curenta = data
                log(f"  OK ziua {data} selectata", C.GREEN)

            # 9b. Gasesc randul in Sectiunea 2
            log(f"  Caut tranzactia id_nota={id_nota} in Sectiunea 2...", C.BLUE)
            s2_row = find_section2_row(driver, id_nota, nr_doc)
            if not s2_row:
                log(f"  EROARE: randul nu a fost gasit in Sectiunea 2", C.RED)
                status_final = 'EROARE_ROW'
                rezultate.append({**tranz, 'reconciliat': status_final})
                continue
            log(f"  OK rand gasit in Sectiunea 2", C.GREEN)

            # 9c. Click pe rand pentru selectie
            try:
                s2_row.click()
            except Exception:
                driver.execute_script("arguments[0].click();", s2_row)
            time.sleep(0.5)

            # 9d. Click Modific
            log(f"  Apas Modific...", C.BLUE)
            if not click_modific(driver, wait):
                status_final = 'EROARE_MODIFIC'
                rezultate.append({**tranz, 'reconciliat': status_final})
                continue
            time.sleep(2)

            # 9e. Astept Sectiunea 3
            log(f"  Astept facturile in Sectiunea 3...", C.BLUE)
            s3_loaded = wait_section3_loaded(driver, timeout=10)
            if not s3_loaded:
                log(f"  ATENTIE: Sectiunea 3 nu are facturi!", C.YELLOW)
                click_renunt(driver)
                status_final = 'FARA_FACTURI'
                rezultate.append({**tranz, 'reconciliat': status_final})
                continue

            # 9f. Citesc facturile
            s3_rows = get_section3_rows(driver)
            log(f"  Gasit {len(s3_rows)} facturi in Sectiunea 3", C.CYAN)
            for f_row in s3_rows:
                log(f"    {f_row['nr_factura']:20s} | {f_row['data_fact']} | Neachitat: {f_row['neachitat_real']:.2f}", C.RESET)

            # 9g. Aplica FIFO
            log(f"  Aplica logica FIFO (DRY_RUN={DRY_RUN})...", C.BLUE)
            ok_match, suma_proc, detalii_final = apply_fifo_matching(
                driver, s3_rows, suma, dry_run=DRY_RUN
            )

            if not ok_match:
                log(f"  EROARE matching: {detalii_final}", C.RED)
                click_renunt(driver)
                status_final = 'EROARE_MATCHING'
                rezultate.append({**tranz, 'reconciliat': status_final})
                continue

            # 9h. Salveaza (sau simuleaza)
            if DRY_RUN:
                log(f"  DRY RUN: NU se salveaza. Apas Renunt...", C.YELLOW)
                click_renunt(driver)
                status_final = 'DRY_RUN_OK'
            else:
                log(f"  Apas Salvez...", C.BLUE)
                if click_salvez(driver, wait):
                    time.sleep(2)
                    wait_for_view_mode(driver, timeout=15)
                    status_final = 'RECONCILIAT'
                    log(f"  OK SALVAT - {suma_proc:.2f} RON reconciliat", C.GREEN)
                else:
                    status_final = 'EROARE_SALVEZ'
                    try:
                        driver.find_element(
                            By.XPATH, "//button[.//span[normalize-space()='Renunt']]"
                        ).click()
                        time.sleep(1)
                    except Exception:
                        pass

            rezultate.append({**tranz, 'reconciliat': status_final})

        except Exception as e:
            log(f"  EXCEPTIE neasteptata: {e}", C.RED)
            import traceback
            traceback.print_exc()
            try:
                click_renunt(driver)
                time.sleep(1)
            except Exception:
                pass
            status_final = 'EXCEPTIE'
            rezultate.append({**tranz, 'reconciliat': status_final})

        # Reset ziua_curenta daca s-a produs o eroare
        if status_final not in ('DRY_RUN_OK', 'RECONCILIAT'):
            ziua_curenta = None

    # ------------------------------------------------------------------
    # 10. Salvez CSV actualizat cu statusurile
    # ------------------------------------------------------------------
    log("\n10. Salvez CSV actualizat cu statusuri...", C.BLUE)
    if rezultate:
        fieldnames_out = list(rezultate[0].keys())
        with open(CSV_FILE, 'w', newline='', encoding='utf-8-sig') as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames_out, delimiter=';')
            writer.writeheader()
            writer.writerows(rezultate)
        log(f"   OK CSV actualizat: {CSV_FILE}", C.GREEN)

    # ------------------------------------------------------------------
    # 11. Sumar final
    # ------------------------------------------------------------------
    ok_count  = sum(1 for r in rezultate if r['reconciliat'] == 'RECONCILIAT')
    dry_count = sum(1 for r in rezultate if r['reconciliat'] == 'DRY_RUN_OK')
    err_count = sum(1 for r in rezultate if r['reconciliat'] not in ('RECONCILIAT', 'DRY_RUN_OK'))

    log("\n" + "=" * 70, C.BLUE)
    log("SUMAR FINAL:", C.BOLD)
    log(f"  Tranzactii scanate:   {len(de_reconciliat)}", C.CYAN)
    log(f"  Tranzactii procesate: {len(rezultate)}", C.CYAN)
    if DRY_RUN:
        log(f"  DRY RUN OK:           {dry_count}  (nicio modificare salvata)", C.YELLOW)
    else:
        log(f"  Reconciliate OK:      {ok_count}", C.GREEN)
    log(f"  Erori / skip:         {err_count}", C.RED if err_count else C.RESET)
    if DRY_RUN:
        log("\n  *** Rezultatele sunt OK? Re-ruleaza si alege LIVE pentru salvare reala. ***", C.YELLOW)
    log("=" * 70, C.BLUE)

    log("\n(Browser ramane deschis - verifica rezultatele in SAGA)", C.YELLOW)
    input("\nApasa Enter pentru a inchide aceasta consola (Chrome ramane deschis)...")
    # Nu apelam driver.quit() - Chrome ramane deschis pentru alte scripturi

except Exception as e:
    log(f"\nERROR GLOBAL: {str(e)}", C.RED)
    import traceback
    traceback.print_exc()
    if driver is not None:
        try:
            input("\nA aparut o eroare. Apasa Enter pentru a inchide browser...")
            driver.quit()
        except Exception:
            pass
    sys.exit(1)
