import os
import socket
import time
import datetime
import json
import mysql.connector

# Remote DB config (same DB used by the webapp)
DB_HOST = "192.168.1.70"
DB_USER = "root"
DB_PASS = "root1940"
DB_NAME = "smproduce_prod"

# Files
BASE_DIR = os.path.dirname(__file__)
LAST_PATH = os.path.join(BASE_DIR, "last_keyence_message.txt")
CFG_PATH = os.path.abspath(os.path.join(BASE_DIR, "..", "config", "keyence.json"))

SCANS_TABLE_SQL = """
CREATE TABLE IF NOT EXISTS keyence_scans (
    id INT AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(255) NOT NULL,
    raw_payload TEXT,
    source_ip VARCHAR(45),
    received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
"""

def load_keyence_cfg():
    cfg = {"ip": "192.168.1.180", "port": 8610, "enabled": True}
    try:
        if os.path.isfile(CFG_PATH):
            with open(CFG_PATH, "r", encoding="utf-8") as f:
                tmp = json.load(f)
            if isinstance(tmp, dict):
                cfg.update(tmp)
    except Exception as e:
        print("[CFG] Error reading keyence.json:", e)
    # sanitize
    cfg["ip"] = str(cfg.get("ip", "192.168.1.180")).strip() or "192.168.1.180"
    try:
        cfg["port"] = int(cfg.get("port", 8610))
    except Exception:
        cfg["port"] = 8610
    if cfg["port"] <= 0 or cfg["port"] > 65535:
        cfg["port"] = 8610
    cfg["enabled"] = bool(cfg.get("enabled", True))
    return cfg

def get_db():
    return mysql.connector.connect(
        host=DB_HOST,
        user=DB_USER,
        password=DB_PASS,
        database=DB_NAME,
        autocommit=True,
    )

def ensure_table(conn):
    cur = conn.cursor()
    cur.execute(SCANS_TABLE_SQL)
    cur.close()

def insert_scan(conn, code, raw_payload, source_ip):
    cur = conn.cursor()
    cur.execute(
        "INSERT INTO keyence_scans(code, raw_payload, source_ip, received_at) VALUES (%s,%s,%s,NOW())",
        (code, raw_payload, source_ip),
    )
    cur.close()

def touch_last_file():
    try:
        with open(LAST_PATH, "a", encoding="utf-8"):
            pass
    except Exception as e:
        print("[FS] Error touching last message file:", e)

def write_last(code, ip, ts):
    try:
        with open(LAST_PATH, "w", encoding="utf-8") as f:
            f.write(f"{ts} | {ip} | {code}")
    except Exception as e:
        print("[FS] Error writing last message:", e)

def parse_lines(payload: str):
    # Keyence may send multiple lines in one packet
    lines = []
    for part in payload.replace("\r\n", "\n").split("\n"):
        t = part.strip()
        if t:
            lines.append(t)
    return lines

def main():
    db = None
    touch_last_file()

    while True:
        cfg = load_keyence_cfg()
        if not cfg.get("enabled", True):
            print("[CFG] Keyence listener disabled in keyence.json. Sleeping 5s...")
            time.sleep(5)
            continue

        keyence_ip = cfg["ip"]
        keyence_port = cfg["port"]

        try:
            if db is None or not db.is_connected():
                db = get_db()
                ensure_table(db)
                print("[DB] Connected to", DB_HOST)

            print(f"[TCP] Connecting to {keyence_ip}:{keyence_port}...")
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(5)
            s.connect((keyence_ip, keyence_port))
            s.settimeout(None)
            print("[TCP] Connected. Waiting for data...")

            buf = ""
            while True:
                data = s.recv(4096)
                if not data:
                    print("[TCP] Connection closed by device.")
                    break

                text = data.decode(errors="ignore")
                if not text:
                    continue

                buf += text

                # Process complete lines when possible
                if "\n" in buf or "\r" in buf:
                    lines = parse_lines(buf)
                    buf = ""
                else:
                    lines = parse_lines(buf)
                    buf = "" if lines else buf

                for line in lines:
                    ts = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    print(f"[RX] {ts} | {line}")
                    try:
                        insert_scan(db, line, line, keyence_ip)
                    except Exception as e:
                        print("[DB] Error inserting scan:", e)
                        try:
                            db.close()
                        except Exception:
                            pass
                        db = None
                    write_last(line, keyence_ip, ts)

            try:
                s.close()
            except Exception:
                pass
            time.sleep(2)

        except Exception as e:
            print("[MAIN] Error:", e)
            time.sleep(5)

if __name__ == "__main__":
    main()
