# -*- coding: utf-8 -*-

from datetime import datetime, timedelta, timezone
from email.message import EmailMessage
import json
import os
from pathlib import Path
import shutil
import smtplib
import subprocess
import time
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

try:
    import mysql.connector
except ImportError:
    mysql = None
else:
    mysql = mysql.connector

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoAlertPresentException, TimeoutException


# Versao para cron/servidor: roda em headless e sem pausas longas de inspecao.
DEBUG = False
USAR_BANCO = True
TESTAR_SOMENTE_BANCO = False
LIMITE_COLETAS = 5
DIAS_RETROATIVOS = 0
PAUSA_ENTRE_COLETAS = 3
PAUSA_APOS_CLIQUE_COLETAR = 5
PAUSA_APOS_CONFIRMACAO_COLETA = 1
PAUSA_REQUISICAO_ANDAMENTO = 8
MAX_TENTATIVAS_PESQUISA = 3
EMAIL_ALERTA_ATIVO = True
EMAIL_DESTINATARIO = "suporte@kreativesistemas.com.br"
EMAIL_REMETENTE = "suporte@kreativesistemas.com.br"
INTERVALO_ALERTA_FATAL_SEGUNDOS = 30 * 60

# Se SMTP_HOST ficar vazio, no servidor Linux o script tenta usar sendmail.
SMTP_HOST = ""
SMTP_PORT = 587
SMTP_USUARIO = ""
SMTP_SENHA = ""
SMTP_USAR_TLS = True
try:
    TIMEZONE = ZoneInfo("America/Sao_Paulo")
except ZoneInfoNotFoundError:
    TIMEZONE = timezone(timedelta(hours=-3))

# ==============================
# CONFIGURACOES DE LOGIN SSW
# ==============================

DOMINIO = "BMO"
CPF = "25594231897"
USUARIO = "fabio"
SENHA = "26200209"

# ==============================
# CONFIGURACOES DO BANCO
# ==============================

DB_CONFIG = {
    "host": "177.234.148.42",
    "user": "ksoftlogcom_user",
    "password": "a7850254fdac",
    "database": "ksoftlogcom_bemol",
}

# Use este bloco para testar localmente sem banco.
# No servidor, altere USAR_BANCO para True.
COLETAS_TESTE = [
    {"Cod": 1, "filial": "CWB", "Cte": "063608"},
    {"Cod": 2, "filial": "CWB", "Cte": "063603"},
    {"Cod": 3, "filial": "CWB", "Cte": "063613"},
]

# ==============================
# CONFIGURACOES DO SSW
# ==============================

PROGRAMA = "003"
URL_LOGIN = "https://sistema.ssw.inf.br/bin/ssw0422"
URL_MENU = "https://sistema.ssw.inf.br/bin/menu01"


class PhpMysqlConnection:
    def close(self):
        pass

    def is_connected(self):
        return True

    def reconnect(self, attempts=3, delay=2):
        return True


def executar_mysql_php(sql, params=None, fetch=False):
    php_bin = shutil.which("php")
    if not php_bin:
        raise RuntimeError(
            "Modulo mysql-connector-python nao encontrado e comando php nao esta disponivel."
        )

    payload = {
        "config": DB_CONFIG,
        "sql": sql.replace("%s", "?"),
        "params": list(params or []),
        "types": "".join("i" if isinstance(valor, int) else "s" for valor in (params or [])),
        "fetch": fetch,
    }

    php_code = r'''
$payload = json_decode(stream_get_contents(STDIN), true);
$cfg = $payload["config"];
$conn = new mysqli($cfg["host"], $cfg["user"], $cfg["password"], $cfg["database"]);
if ($conn->connect_errno) {
    fwrite(STDERR, "Erro MySQL: " . $conn->connect_error);
    exit(1);
}
$conn->set_charset("utf8mb4");
$stmt = $conn->prepare($payload["sql"]);
if (!$stmt) {
    fwrite(STDERR, "Erro prepare: " . $conn->error);
    exit(1);
}
$params = $payload["params"];
if (count($params) > 0) {
    $stmt->bind_param($payload["types"], ...$params);
}
if (!$stmt->execute()) {
    fwrite(STDERR, "Erro execute: " . $stmt->error);
    exit(1);
}
if ($payload["fetch"]) {
    $res = $stmt->get_result();
    $rows = [];
    while ($row = $res->fetch_assoc()) {
        $rows[] = $row;
    }
    echo json_encode($rows);
} else {
    echo json_encode(["affected_rows" => $stmt->affected_rows]);
}
'''

    resultado = subprocess.run(
        [php_bin, "-r", php_code],
        input=json.dumps(payload),
        capture_output=True,
        text=True,
        timeout=60,
    )

    if resultado.returncode != 0:
        raise RuntimeError(resultado.stderr.strip() or "Falha ao executar MySQL via PHP.")

    return json.loads(resultado.stdout or "[]")


def conectar_banco():
    if mysql is None:
        print("mysql-connector-python nao encontrado. Usando fallback MySQL via PHP/mysqli.")
        return PhpMysqlConnection()

    return mysql.connect(**DB_CONFIG)


def periodo_busca():
    hoje = datetime.now(TIMEZONE).date()
    data_inicial = hoje - timedelta(days=DIAS_RETROATIVOS)
    return data_inicial.isoformat(), hoje.isoformat()


def buscar_coletas_pendentes(conn, limite=LIMITE_COLETAS):
    data_inicial, data_final = periodo_busca()

    sql_filial = """
        SELECT filial
        FROM itensromaneio
        WHERE status IN ('coletado')
          AND coletado = '0'
          AND DataEmissao BETWEEN %s AND %s
          AND tipomov = 'COL'
          AND filial != 'FEC'
          AND data_alteracao <= DATE_SUB(NOW(), INTERVAL 5 MINUTE)
        ORDER BY data_alteracao ASC
        LIMIT 1
    """

    if isinstance(conn, PhpMysqlConnection):
        filiais = executar_mysql_php(sql_filial, (data_inicial, data_final), fetch=True)
        if not filiais:
            return []

        filial_lote = filiais[0]
    else:
        cursor = conn.cursor(dictionary=True)
        cursor.execute(sql_filial, (data_inicial, data_final))
        filial_lote = cursor.fetchone()

        if not filial_lote:
            cursor.close()
            return []

    sql = """
        SELECT
            Cod,
            Cte,
            filial,
            DataEmissao,
            data_alteracao
        FROM itensromaneio
        WHERE status IN ('coletado')
          AND coletado = '0'
          AND DataEmissao BETWEEN %s AND %s
          AND tipomov = 'COL'
          AND filial != 'FEC'
          AND data_alteracao <= DATE_SUB(NOW(), INTERVAL 5 MINUTE)
          AND filial = %s
        ORDER BY data_alteracao ASC
        LIMIT %s
    """

    params = (data_inicial, data_final, filial_lote["filial"], limite)

    if isinstance(conn, PhpMysqlConnection):
        coletas = executar_mysql_php(sql, params, fetch=True)
    else:
        cursor.execute(sql, params)
        coletas = cursor.fetchall()
        cursor.close()

    return coletas


def marcar_coleta_baixada(conn, cod):
    if isinstance(conn, PhpMysqlConnection):
        sql = """
            UPDATE itensromaneio
            SET coletado = '1'
            WHERE Cod = %s
            LIMIT 1
        """
        executar_mysql_php(sql, (cod,), fetch=False)
        return

    if not conn.is_connected():
        print("Conexao MySQL indisponivel. Reconectando antes do UPDATE...")
        conn.reconnect(attempts=3, delay=2)

    sql = """
        UPDATE itensromaneio
        SET coletado = '1'
        WHERE Cod = %s
        LIMIT 1
    """

    cursor = conn.cursor()
    cursor.execute(sql, (cod,))
    conn.commit()
    cursor.close()


def marcar_coleta_nao_baixada(conn, cod):
    sql = """
        UPDATE itensromaneio
        SET coletado = '2'
        WHERE Cod = %s
          AND coletado = '0'
        LIMIT 1
    """

    if isinstance(conn, PhpMysqlConnection):
        executar_mysql_php(sql, (cod,), fetch=False)
        return

    if not conn.is_connected():
        print("Conexao MySQL indisponivel. Reconectando antes de marcar a falha...")
        conn.reconnect(attempts=3, delay=2)

    cursor = conn.cursor()
    cursor.execute(sql, (cod,))
    conn.commit()
    cursor.close()


def enviar_mensagem_email(assunto, corpo):
    mensagem = EmailMessage()
    mensagem["From"] = EMAIL_REMETENTE
    mensagem["To"] = EMAIL_DESTINATARIO
    mensagem["Subject"] = assunto
    mensagem.set_content(corpo)

    try:
        if SMTP_HOST:
            with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=30) as smtp:
                if SMTP_USAR_TLS:
                    smtp.starttls()
                if SMTP_USUARIO:
                    smtp.login(SMTP_USUARIO, SMTP_SENHA)
                smtp.send_message(mensagem)
        else:
            sendmail = shutil.which("sendmail") or "/usr/sbin/sendmail"
            subprocess.run(
                [sendmail, "-t", "-oi"],
                input=mensagem.as_bytes(),
                check=True,
                timeout=30,
            )

        print(f"Alerta enviado para {EMAIL_DESTINATARIO}.")
        return True

    except Exception as exc:
        print(f"Nao foi possivel enviar alerta por email: {exc}")
        return False


def enviar_alerta_email(cod, filial, numero_coleta, erro, retirada_fila=False):
    if not EMAIL_ALERTA_ATIVO:
        return

    assunto = f"[SSW] Coleta nao baixada - {numero_coleta}"
    situacao_integracao = (
        "Marcada como nao baixada (coletado = 2) e retirada da fila automatica."
        if retirada_fila
        else "Nao foi possivel retirar automaticamente esta coleta da fila; requer verificacao."
    )
    corpo = f"""A coleta nao pode ser baixada apos as tentativas configuradas.

Cod: {cod}
Filial: {filial}
Coleta/Cte: {numero_coleta}
Data/hora: {datetime.now(TIMEZONE).strftime('%Y-%m-%d %H:%M:%S')}

Erro:
{erro}

Situacao na integracao: {situacao_integracao}
"""
    enviar_mensagem_email(assunto, corpo)


def enviar_alerta_fatal(erro):
    if not EMAIL_ALERTA_ATIVO:
        return

    arquivo_controle = Path(__file__).resolve().with_name(".baixar_coletas_alerta_fatal")
    agora = time.time()
    try:
        ultimo_alerta = float(arquivo_controle.read_text(encoding="utf-8").strip())
    except (OSError, ValueError):
        ultimo_alerta = 0

    restante = INTERVALO_ALERTA_FATAL_SEGUNDOS - (agora - ultimo_alerta)
    if restante > 0:
        print(f"Alerta fatal suprimido pelo intervalo de 30 minutos ({int(restante)}s restantes).")
        return

    assunto = "[SSW] Automacao de coletas interrompida"
    corpo = f"""A automacao SSW de baixa de coletas foi interrompida antes de concluir o processamento.

Arquivo: {Path(__file__).name}
Data/hora: {datetime.now(TIMEZONE).strftime('%Y-%m-%d %H:%M:%S')}
Novo alerta permitido apos: 30 minutos

Erro:
{erro}
"""
    if enviar_mensagem_email(assunto, corpo):
        arquivo_temporario = arquivo_controle.with_suffix(".tmp")
        try:
            arquivo_temporario.write_text(str(agora), encoding="utf-8")
            arquivo_temporario.replace(arquivo_controle)
        except OSError as exc:
            print(f"Nao foi possivel atualizar o controle do alerta fatal: {exc}")


def criar_driver():
    options = Options()

    if DEBUG:
        options.add_experimental_option("detach", True)
    else:
        options.add_argument("--headless=new")

    options.add_argument("--window-size=1200,800")
    options.add_argument("--disable-gpu")
    options.add_argument("--disable-extensions")
    options.add_argument("--disable-notifications")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-setuid-sandbox")
    options.add_argument("--disable-dev-shm-usage")

    chrome_bin = os.getenv("CHROME_BINARY")
    if chrome_bin:
        options.binary_location = chrome_bin
    elif not DEBUG:
        for candidato in ("google-chrome", "google-chrome-stable", "chromium", "chromium-browser"):
            caminho = shutil.which(candidato)
            if caminho:
                options.binary_location = caminho
                break

    chromedriver_path = os.getenv("CHROMEDRIVER_PATH")
    if not chromedriver_path and not DEBUG:
        for candidato in ("/usr/bin/chromedriver", "/usr/local/bin/chromedriver"):
            if os.path.exists(candidato):
                chromedriver_path = candidato
                break

    service = Service(chromedriver_path) if chromedriver_path else Service(ChromeDriverManager().install())

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


def obter_data_coletada(driver):
    return driver.execute_script("""
        const dataRegex = /\\b\\d{2}\\/\\d{2}\\/\\d{2}\\s+\\d{2}:\\d{2}\\b/;
        const px = (value) => Number(String(value || '').replace('px', '')) || 0;
        const labels = Array.from(document.querySelectorAll('div.texto'));
        const label = labels.find((el) =>
            (el.textContent || '').replace(/\\u00a0/g, ' ').includes('Coletada')
        );

        if (!label) {
            return '';
        }

        const top = label.style.top;
        const labelLeft = px(label.style.left);
        const dataMesmoTop = Array.from(document.querySelectorAll('div.data')).find((el) =>
            el.style.top === top &&
            px(el.style.left) > labelLeft &&
            dataRegex.test((el.textContent || '').trim())
        );

        if (dataMesmoTop) {
            return dataMesmoTop.textContent.trim();
        }

        let proximo = label.nextElementSibling;
        while (proximo) {
            const texto = (proximo.textContent || '').trim();
            if (
                proximo.classList &&
                proximo.classList.contains('data') &&
                dataRegex.test(texto)
            ) {
                return texto;
            }
            proximo = proximo.nextElementSibling;
        }

        return '';
    """)


def realizar_login(driver):
    print("Acessando tela de login...")
    driver.get(URL_LOGIN)
    time.sleep(5)

    print("Realizando login...")
    driver.find_element(By.ID, "1").send_keys(DOMINIO)
    driver.find_element(By.ID, "2").send_keys(CPF)
    driver.find_element(By.ID, "3").send_keys(USUARIO)
    driver.find_element(By.ID, "4").send_keys(SENHA)
    driver.find_element(By.ID, "5").click()
    time.sleep(5)

    print("Login efetuado com sucesso.")


def abrir_programa_003(driver, filial):
    print("Acessando menu principal...")
    driver.get(URL_MENU)
    time.sleep(3)

    janela_menu = driver.current_window_handle

    print(f"Selecionando filial: {filial}")
    campo_filial = driver.find_element(By.ID, "2")
    campo_filial.clear()
    campo_filial.send_keys(filial)

    driver.execute_script(
        "arguments[0].dispatchEvent(new Event('change'));",
        campo_filial,
    )

    print("Filial atual:", campo_filial.get_attribute("value"))
    time.sleep(1)

    print(f"Informando programa: {PROGRAMA}")
    campo_programa = driver.find_element(By.ID, "3")
    campo_programa.clear()
    campo_programa.send_keys(PROGRAMA)
    time.sleep(2)

    try:
        alerta = driver.switch_to.alert
        print("ALERTA ENCONTRADO:")
        print(alerta.text)
        alerta.accept()
        print("Alerta fechado automaticamente.")
    except NoAlertPresentException:
        print("Nenhum alerta encontrado.")

    print("Aguardando abertura do SSW0018...")

    WebDriverWait(driver, 20).until(lambda navegador: len(navegador.window_handles) > 1)

    for handle in driver.window_handles:
        if handle != janela_menu:
            driver.switch_to.window(handle)
            break

    janela_coleta = driver.current_window_handle

    print("Janela SSW0018 aberta.")
    print("URL atual:", driver.current_url)

    if "ssw0018" not in driver.current_url.lower():
        print("Aviso: URL inesperada.")
        print(driver.current_url)

    return janela_menu, janela_coleta


def fechar_janelas_detalhe(driver, janela_menu, janela_coleta):
    janelas_fixas = {janela_menu, janela_coleta}
    janelas_para_fechar = [
        handle for handle in driver.window_handles
        if handle not in janelas_fixas
    ]

    for handle in janelas_para_fechar:
        try:
            driver.switch_to.window(handle)
            aceitar_alerta_se_existir(driver)
            driver.close()
            print("Janela de detalhe fechada.")
        except Exception as exc:
            print(f"Nao foi possivel fechar uma janela de detalhe: {exc}")

    if janela_coleta in driver.window_handles:
        driver.switch_to.window(janela_coleta)
    elif janela_menu in driver.window_handles:
        driver.switch_to.window(janela_menu)

    aceitar_alerta_se_existir(driver)


def fechar_janelas_ssw(driver):
    for handle in list(driver.window_handles):
        try:
            driver.switch_to.window(handle)
            aceitar_alerta_se_existir(driver)
            driver.close()
        except Exception as exc:
            print(f"Nao foi possivel fechar uma janela do SSW: {exc}")


def aceitar_alerta_se_existir(driver):
    try:
        alerta = driver.switch_to.alert
        texto = alerta.text
        print("ALERTA ENCONTRADO:")
        print(texto)
        alerta.accept()
        print("Alerta fechado automaticamente.")
        return texto
    except NoAlertPresentException:
        return None


def confirmar_modal_sim_se_existir(driver, timeout=PAUSA_APOS_CLIQUE_COLETAR):
    fim = time.time() + timeout

    while time.time() < fim:
        modal = driver.execute_script("""
            const box = document.getElementById('errormsg');
            if (!box || box.style.visibility === 'hidden') {
                return null;
            }

            const texto = (box.innerText || '').replace(/\\s+/g, ' ').trim();
            const botoes = Array.from(box.querySelectorAll('a.dialog'));
            const botaoSim = botoes.find((el) => (el.textContent || '').trim().includes('Sim'));

            if (!botaoSim) {
                return {encontrado: true, clicado: false, texto};
            }

            botaoSim.click();
            return {encontrado: true, clicado: true, texto};
        """)

        if modal and modal.get("encontrado"):
            print("Modal de confirmacao encontrado:")
            print(modal.get("texto", ""))

            if modal.get("clicado"):
                print("Opcao 'Sim' selecionada automaticamente.")
                time.sleep(2)
                return True

            print("Modal encontrado, mas o botao 'Sim' nao foi localizado.")
            return False

        time.sleep(1)

    return False


def tela_detalhe_carregada(driver):
    url = driver.current_url.lower()

    if "blank.html" in url:
        return False

    return driver.execute_script("""
        const texto = document.body ? (document.body.innerText || '') : '';
        return Boolean(
            document.getElementById('link_col') ||
            texto.includes('Coletada')
        );
    """)


def pesquisar_coleta(driver, janela_menu, janela_coleta, numero_coleta):
    driver.switch_to.window(janela_coleta)

    for tentativa in range(1, MAX_TENTATIVAS_PESQUISA + 1):
        aceitar_alerta_se_existir(driver)

        print(f"\nInformando coleta: {numero_coleta}")
        campo_coleta = WebDriverWait(driver, 20).until(
            EC.presence_of_element_located((By.ID, "7"))
        )
        campo_coleta.clear()
        campo_coleta.send_keys(str(numero_coleta).zfill(6))

        print("Coleta informada:", campo_coleta.get_attribute("value"))
        time.sleep(1)

        handles_anteriores = set(driver.window_handles)

        print(
            "Clicando na seta para pesquisar a coleta "
            f"(tentativa {tentativa}/{MAX_TENTATIVAS_PESQUISA})..."
        )
        botao_avancar = driver.find_element(By.ID, "8")
        driver.execute_script("arguments[0].click();", botao_avancar)
        time.sleep(1)

        alerta = aceitar_alerta_se_existir(driver)

        if alerta:
            print(
                "SSW ainda tem requisicao em andamento. "
                f"Aguardando {PAUSA_REQUISICAO_ANDAMENTO}s para tentar novamente..."
            )
            time.sleep(PAUSA_REQUISICAO_ANDAMENTO)
            driver.switch_to.window(janela_coleta)
            continue

        print("Aguardando abertura da tela da coleta...")

        for _ in range(20):
            handles_novos = [h for h in driver.window_handles if h not in handles_anteriores]
            if handles_novos:
                janela_detalhe = handles_novos[0]
                driver.switch_to.window(janela_detalhe)
                print("Tela da coleta aberta em nova janela.")
                print("URL atual:", driver.current_url)

                try:
                    WebDriverWait(driver, 25).until(tela_detalhe_carregada)
                    print("Tela de detalhe carregada.")
                    print("URL atual:", driver.current_url)
                    return janela_detalhe
                except TimeoutException:
                    print("Tela de detalhe ficou em branco ou sem conteudo esperado.")
                    driver.close()
                    driver.switch_to.window(janela_coleta)
                    time.sleep(PAUSA_REQUISICAO_ANDAMENTO)
                    break
            time.sleep(1)

        print("Tela de detalhe nao abriu nessa tentativa.")

    raise Exception(
        "Nao foi possivel abrir a tela de detalhe da coleta apos "
        f"{MAX_TENTATIVAS_PESQUISA} tentativas."
    )


def baixar_coleta(driver):
    data_coletada = obter_data_coletada(driver)

    if data_coletada:
        print(f"Coleta ja estava baixada em: {data_coletada}")
        print("Clique no botao Coletar ignorado para evitar baixa duplicada.")
        return "ja_baixada", data_coletada

    print("Aguardando botao Coletar...")
    wait = WebDriverWait(driver, 20)
    try:
        botao_coletar = wait.until(EC.element_to_be_clickable((By.ID, "link_col")))
    except TimeoutException:
        raise Exception(
            "Botao Coletar nao apareceu na tela de detalhe. "
            f"URL atual: {driver.current_url}"
        )

    print("Botao Coletar encontrado. Clicando para baixar a coleta...")
    driver.execute_script("arguments[0].click();", botao_coletar)
    print(
        "Aguardando "
        f"{PAUSA_APOS_CLIQUE_COLETAR}s para verificar possivel modal Sim/Nao..."
    )
    confirmou_modal = confirmar_modal_sim_se_existir(driver)
    if not confirmou_modal:
        time.sleep(PAUSA_APOS_CLIQUE_COLETAR)
    aceitar_alerta_se_existir(driver)

    print("Baixa acionada. Aguardando confirmacao da data coletada...")

    try:
        data_coletada = wait.until(lambda navegador: obter_data_coletada(navegador))
    except TimeoutException:
        raise Exception(
            "A baixa foi acionada, mas a data de 'Coletada' nao foi preenchida "
            "no tempo esperado."
        )

    print(f"Coleta baixada com sucesso em: {data_coletada}")
    print(
        "Aguardando "
        f"{PAUSA_APOS_CONFIRMACAO_COLETA}s antes de sair da tela da coleta..."
    )
    time.sleep(PAUSA_APOS_CONFIRMACAO_COLETA)
    return "baixada", data_coletada


def testar_banco():
    print("=" * 60)
    print("Testando conexao e busca no banco")
    print("=" * 60)

    conn = conectar_banco()

    try:
        coletas = buscar_coletas_pendentes(conn)

        if not coletas:
            print("Conexao OK. Nenhum registro encontrado pelo select.")
            return

        print(f"Conexao OK. Coletas encontradas: {len(coletas)}")

        for coleta in coletas:
            print(
                f"Cod={coleta['Cod']} | "
                f"filial={coleta['filial']} | "
                f"Cte={coleta['Cte']} | "
                f"DataEmissao={coleta['DataEmissao']} | "
                f"data_alteracao={coleta['data_alteracao']}"
            )

    finally:
        conn.close()


def processar_coletas():
    print("=" * 60)
    print("Iniciando automacao SSW - baixa de coletas")
    print("=" * 60)

    conn = None
    driver = None

    try:
        if USAR_BANCO:
            conn = conectar_banco()
            coletas = buscar_coletas_pendentes(conn)
        else:
            coletas = COLETAS_TESTE

        if not coletas:
            print("Nenhum registro encontrado.")
            return

        filial = coletas[0]["filial"]
        print(f"Coletas encontradas: {len(coletas)}")
        print(f"Filial do lote: {filial}")

        driver = criar_driver()
        realizar_login(driver)
        janela_menu, janela_coleta = abrir_programa_003(driver, filial)

        for coleta in coletas:
            cod = coleta["Cod"]
            numero_coleta = coleta["Cte"]
            janela_detalhe = None

            if not numero_coleta:
                print(f"\nRegistro Cod {cod} ignorado: campo Cte vazio.")
                continue

            try:
                janela_detalhe = pesquisar_coleta(driver, janela_menu, janela_coleta, numero_coleta)
                status, data_coletada = baixar_coleta(driver)

                if USAR_BANCO:
                    marcar_coleta_baixada(conn, cod)

                    print(
                        f"Registro Cod {cod} marcado como coletado = '1' "
                        f"({status}, {data_coletada})."
                    )
                else:
                    print(
                        f"Modo teste: Registro Cod {cod} seria marcado como "
                        f"coletado = '1' ({status}, {data_coletada})."
                    )

            except Exception as exc:
                print(f"Erro ao processar Cod {cod}, coleta {numero_coleta}: {exc}")
                retirada_fila = False
                if USAR_BANCO:
                    try:
                        marcar_coleta_nao_baixada(conn, cod)
                        retirada_fila = True
                        print(f"Registro Cod {cod} marcado como coletado = '2' (nao baixada).")
                    except Exception as erro_marcacao:
                        print(f"Nao foi possivel retirar o Cod {cod} da fila automatica: {erro_marcacao}")
                enviar_alerta_email(cod, filial, numero_coleta, exc, retirada_fila)

            finally:
                fechar_janelas_detalhe(driver, janela_menu, janela_coleta)
                print(f"Aguardando {PAUSA_ENTRE_COLETAS}s antes da proxima coleta...")
                time.sleep(PAUSA_ENTRE_COLETAS)

        print("\nProcessamento finalizado.")

        fechar_janelas_ssw(driver)
        driver = None

        if DEBUG:
            print("\nModo DEBUG ativo.")
            print("Janelas do SSW fechadas apos o fim do lote.")

    finally:
        if conn is not None:
            conn.close()

        if driver is not None:
            if DEBUG:
                print("\nModo DEBUG ativado.")
                print("Chrome mantido aberto para inspecao.")
            else:
                driver.quit()


if __name__ == "__main__":
    try:
        if TESTAR_SOMENTE_BANCO:
            testar_banco()
        else:
            processar_coletas()
    except Exception as exc:
        print(f"Erro fatal na automacao: {exc}")
        enviar_alerta_fatal(exc)
        raise
