import socket
import time
import csv
from datetime import datetime
import threading

csv_lock = threading.Lock()  # 防止多线程写CSV冲突

def scan_once(ip="192.168.1.50", port_in=2001, port_out=2002,
              csv_file="scan_results.csv", timeout=5, retries=3):
    """
    改进版扫码函数：
    - 自动重试
    - 全程超时保护
    - 更安全的socket关闭
    - 文件写入加锁
    """
    def save_result(qrcode):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        with csv_lock:
            with open(csv_file, mode="a", newline="") as f:
                writer = csv.writer(f)
                writer.writerow([timestamp, qrcode])
        print(f"✅ 已保存结果: {timestamp}, {qrcode}")

    result = None

    for attempt in range(1, retries + 1):
        print(f"\n🟡 扫码尝试 {attempt}/{retries} ...")

        try:
            # -------- Step 1: 触发拍照 --------
            with socket.create_connection((ip, port_in), timeout=2) as client_in:
                cmd = "start"
                client_in.sendall(cmd.encode("ascii"))  #把字符串转为byte字节流规则是ascii码
                print(f"→ 已发送触发指令: {cmd}")

            # -------- Step 2: 等待识别结果 --------
            with socket.create_connection((ip, port_out), timeout=timeout) as client_out:
                print(f" 已连接相机输出端口 {port_out}，等待结果...")

                # recv最多阻塞timeout秒
                client_out.settimeout(timeout)
                data = client_out.recv(2048).decode("ascii", errors="ignore").strip() #结果输出为ascii字符串，遇到无法解析的字节则忽略
                # .strip()：去掉字符串头尾的空白字符（包括 \n, \r, 空格等），便于后续判断是否为空或写入 CSV。
                if data:
                    print(f"📷 识别结果: {data}")
                    save_result(data)   #调用 save_result(data) 把时间戳 + 识别字符串写入 CSV（线程安全）。
                    result = data       #把局部变量 result 设为 data，用于函数返回值
                    break               #如果读取成功跳出重试循环（for attempt in ...），不再进行后续重试。
                else:
                    print("⚠️ 相机返回空数据，重试中...")

        except socket.timeout:
            print("⏰ 超时未收到识别结果，重试中...")
        except ConnectionRefusedError:
            print("❌ 无法连接到扫码器端口，请检查设备是否在线。")
        except OSError as e:
            print(f"⚠️ 网络错误: {e}")
        except Exception as e:
            print(f"❌ 未知异常: {e}")

        time.sleep(0.5)  # 两次扫描之间稍作延时

    # -------- Step 3: 返回最终结果 --------
    if result:
        print(f"✅ 扫码成功：{result}")
    else:
        print("❌ 多次尝试后仍未获取二维码结果")

    return result
