import tkinter as tk
try:
    import tkintermapview
except ImportError:
    tkintermapview = None
from tkinter import scrolledtext, filedialog, messagebox, ttk, simpledialog
import requests
import json
import os
import re
import asyncio
import threading
import sys
try:
    import edge_tts
except ImportError:
    edge_tts = None

try:
    from playsound3 import playsound
except ImportError:
    playsound = None
from pypdf import PdfReader
from docx import Document
import sqlite3
import imaplib
import smtplib
import ssl
import base64
import ctypes
from ctypes import wintypes
from email import message_from_bytes
from email.header import decode_header
from email.message import EmailMessage
from datetime import datetime


# =========================================================
# مسیر فایل‌ها
# =========================================================

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

MEMORY_FILE = os.path.join(BASE_DIR, "ai_memory.json")
CORE_MEMORY_FILE = os.path.join(BASE_DIR, "ai_core_memory.json")
CREATOR_NAME = "امید اسکندری"
CREATOR_NATIONAL_ID = "0322322006"
DB_NAME = os.path.join(BASE_DIR, "anbar.db")
VOICE_FILE = os.path.join(BASE_DIR, "ai_voice.mp3")
EMAIL_CONFIG_FILE = os.path.join(BASE_DIR, "email_config.json")
EMAIL_CREDENTIAL_SERVICE = "ai_local_email"
EMAIL_SECRET_FILE = os.path.join(BASE_DIR, "email_secret.dat")


# =========================================================
# حافظه
# =========================================================

conversation = []
files_data = []


# =========================================================
# دیتابیس
# =========================================================

conn = sqlite3.connect(DB_NAME, check_same_thread=False)
cursor = conn.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    code TEXT UNIQUE NOT NULL,
    name TEXT NOT NULL,
    quantity REAL DEFAULT 0,
    buy_price REAL DEFAULT 0,
    sell_price REAL DEFAULT 0,
    unit TEXT DEFAULT 'عدد'
)
""")

cursor.execute("""
CREATE TABLE IF NOT EXISTS sales (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    product_id INTEGER,
    customer_id INTEGER,
    code TEXT,
    name TEXT,
    quantity REAL,
    price REAL,
    total REAL,
    sale_date TEXT
)
""")

# بررسی فروش‌های قبلی
cursor.execute("PRAGMA table_info(sales)")

sales_columns = [
    row[1]
    for row in cursor.fetchall()
]

if "customer_id" not in sales_columns:

    cursor.execute("""
        ALTER TABLE sales
        ADD COLUMN customer_id INTEGER
    """)

# اطلاعات کارمند ثبت‌کننده فروش
cursor.execute("PRAGMA table_info(sales)")
sales_columns = [row[1] for row in cursor.fetchall()]
if "employee" not in sales_columns:
    cursor.execute("ALTER TABLE sales ADD COLUMN employee TEXT")

# تنظیمات ساده برنامه
cursor.execute("CREATE TABLE IF NOT EXISTS app_settings (key TEXT PRIMARY KEY, value TEXT)")
cursor.execute("SELECT value FROM app_settings WHERE key='active_employee'")
if cursor.fetchone() is None:
    cursor.execute("INSERT INTO app_settings(key,value) VALUES('active_employee','مالک')")

# کارکنان
cursor.execute("""CREATE TABLE IF NOT EXISTS employees (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    role TEXT NOT NULL,
    active INTEGER DEFAULT 1
)""")
for _name, _role in [("علی","انباردار"),("موسی","فروشنده"),("احمد","حسابدار"),("امید","کارپرداز"),("مالک","مالک سیستم")]:
    cursor.execute("INSERT OR IGNORE INTO employees(name,role) VALUES(?,?)", (_name,_role))

# کارپردازی / خرید
cursor.execute("""CREATE TABLE IF NOT EXISTS suppliers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL, phone TEXT, address TEXT, notes TEXT
)""")
cursor.execute("""CREATE TABLE IF NOT EXISTS purchase_requests (
    id INTEGER PRIMARY KEY AUTOINCREMENT, request_no TEXT, supplier_name TEXT,
    product_code TEXT, product_name TEXT, quantity REAL, unit_price REAL,
    total REAL, status TEXT DEFAULT 'در انتظار', request_date TEXT, employee TEXT, notes TEXT
)""")
cursor.execute("""CREATE TABLE IF NOT EXISTS purchases (
    id INTEGER PRIMARY KEY AUTOINCREMENT, request_id INTEGER, supplier_name TEXT,
    product_code TEXT, product_name TEXT, quantity REAL, unit_price REAL,
    total REAL, purchase_date TEXT, employee TEXT
)""")
# ارتقای جدول خریدهای نهایی برای نسخه‌های قدیمی دیتابیس
try:
    cursor.execute("PRAGMA table_info(purchases)")
    _purchase_cols = [r[1] for r in cursor.fetchall()]
    for _col, _definition in [
        ("request_id", "INTEGER"), ("supplier_name", "TEXT"), ("product_code", "TEXT"),
        ("product_name", "TEXT"), ("quantity", "REAL"), ("unit_price", "REAL"),
        ("total", "REAL"), ("purchase_date", "TEXT"), ("employee", "TEXT")
    ]:
        if _col not in _purchase_cols:
            cursor.execute(f"ALTER TABLE purchases ADD COLUMN {_col} {_definition}")
except Exception:
    pass

# وضعیت تأیید حسابداری برای درخواست‌های خرید
try:
    cursor.execute("PRAGMA table_info(purchase_requests)")
    pr_columns = [r[1] for r in cursor.fetchall()]
    for col, definition in [
        ("request_no", "TEXT"),
        ("supplier_name", "TEXT"),
        ("product_code", "TEXT"),
        ("product_name", "TEXT"),
        ("quantity", "REAL"),
        ("unit_price", "REAL"),
        ("total", "REAL"),
        ("status", "TEXT DEFAULT 'در انتظار'"),
        ("request_date", "TEXT"),
        ("employee", "TEXT"),
        ("notes", "TEXT"),
        ("approval_status", "TEXT DEFAULT 'در انتظار تایید حسابداری'"),
        ("approved_by", "TEXT"),
        ("approved_at", "TEXT"),
        ("payment_account", "TEXT"),
        ("product_category", "TEXT DEFAULT 'خوراکی'"),
        ("approved_unit_price", "REAL"),
        ("approved_total", "REAL"),
        ("price_changed_by", "TEXT"),
        ("price_changed_at", "TEXT"),
        ("requested_by", "TEXT"),
        ("financial_status", "TEXT"),
        ("purchased_by", "TEXT"),
        ("purchased_at", "TEXT"),
        ("received_by", "TEXT"),
        ("received_at", "TEXT"),
        ("category", "TEXT DEFAULT 'خوراکی'"),
        ("requester", "TEXT")
    ]:
        if col not in pr_columns:
            cursor.execute(f"ALTER TABLE purchase_requests ADD COLUMN {col} {definition}")
    # مهاجرت ایمن: هیچ درخواست قدیمی بدون تأیید واقعی حسابداری و حساب پرداخت معتبر، مجاز به خرید نیست.
    cursor.execute("""
        UPDATE purchase_requests
        SET approval_status='در انتظار تایید حسابداری',
            status='در انتظار تایید حسابداری',
            payment_account=NULL,
            approved_by=NULL,
            approved_at=NULL
        WHERE approval_status IS NULL
           OR approval_status=''
           OR approval_status='در انتظار'
           OR (approval_status='تایید حسابداری' AND (payment_account IS NULL OR TRIM(payment_account)=''))
    """)
    cursor.execute("UPDATE purchase_requests SET approved_unit_price=unit_price WHERE approval_status='تایید حسابداری' AND approved_unit_price IS NULL")
    cursor.execute("UPDATE purchase_requests SET approved_total=total WHERE approval_status='تایید حسابداری' AND approved_total IS NULL")
except Exception:
    pass

# میانگین موزون بهای خرید کالا برای موجودی و بهای تمام‌شده فروش
try:
    cursor.execute("PRAGMA table_info(products)")
    _product_cols = [r[1] for r in cursor.fetchall()]
    if 'avg_buy_price' not in _product_cols:
        cursor.execute("ALTER TABLE products ADD COLUMN avg_buy_price REAL DEFAULT 0")
    cursor.execute("UPDATE products SET avg_buy_price=COALESCE(buy_price,0) WHERE avg_buy_price IS NULL OR avg_buy_price=0")
except Exception:
    pass
except Exception:
    pass

# ایندکس‌ها برای افزایش سرعت جستجو و گزارش‌گیری
try:
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_products_name ON products(name)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_products_code ON products(code)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_sales_date ON sales(sale_date)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_sales_product ON sales(product_id)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_customers_name ON customers(name)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_accounting_date ON accounting(entry_date)")
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_ledger_date ON ledger_entries(entry_date)")
except Exception:
    pass

conn.commit()

def get_active_employee():
    try:
        cursor.execute("SELECT value FROM app_settings WHERE key='active_employee'")
        row=cursor.fetchone()
        return row[0] if row and row[0] else 'مالک'
    except Exception:
        return 'مالک'

def set_active_employee(name):
    cursor.execute("INSERT OR REPLACE INTO app_settings(key,value) VALUES('active_employee',?)", (str(name),))
    conn.commit()

def log_employee_activity(employee, action, details=''):
    try:
        cursor.execute("INSERT INTO employee_activity(employee,action,details,activity_date) VALUES(?,?,?,?)", (str(employee),str(action),str(details),datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
        conn.commit()
    except Exception:
        pass


# نگاشت نام واقعی کارکنان به نقش سیستمی وظایف
EMPLOYEE_ROLE_MAP = {
    "علی": "کارمند انبار",
    "انباردار": "کارمند انبار",
    "کارمند انبار": "کارمند انبار",
    "موسی": "کارمند فروشگاه",
    "فروشنده": "کارمند فروشگاه",
    "کارمند فروشگاه": "کارمند فروشگاه",
    "احمد": "کارمند حسابداری",
    "حسابدار": "کارمند حسابداری",
    "کارمند حسابداری": "کارمند حسابداری",
    "امید": "کارمند کارپرداز",
    "کارپرداز": "کارمند کارپرداز",
    "کارمند کارپرداز": "کارمند کارپرداز",
    "مالک": "مالک",
    "مالک سیستم": "مالک",
}

EMPLOYEE_DISPLAY = {
    "کارمند انبار": "علی (انباردار)",
    "کارمند فروشگاه": "موسی (فروشنده)",
    "کارمند حسابداری": "احمد (حسابدار)",
    "کارمند کارپرداز": "امید (کارپرداز)",
}

def normalize_employee_role(name):
    """نام واقعی یا نقش را به کلید سیستمی وظایف تبدیل می‌کند."""
    if not name:
        return ""
    name = str(name).strip()
    return EMPLOYEE_ROLE_MAP.get(name, name)

def employee_name_variants(role_or_name):
    """همه نام‌های ممکن یک کارمند برای جستجو در لاگ‌ها."""
    role = normalize_employee_role(role_or_name)
    variants = {role, role_or_name}
    for real, mapped in EMPLOYEE_ROLE_MAP.items():
        if mapped == role:
            variants.add(real)
    return list(variants)

def add_daily_work_log(employee, work_type, quantity=1, unit="مورد", notes="", work_date=None):
    """ثبت کار روزانه واقعی توسط کارمند."""
    work_date = work_date or datetime.now().strftime("%Y-%m-%d")
    emp = str(employee).strip()
    cursor.execute("""
        INSERT INTO employee_daily_logs
        (employee, work_type, quantity, unit, notes, work_date, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    """, (
        emp,
        str(work_type).strip()[:200],
        float(quantity or 1),
        str(unit or "مورد")[:40],
        str(notes or "")[:1000],
        work_date,
        datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
    ))
    conn.commit()
    log_employee_activity(emp, "ثبت کار روزانه", f"{work_type}: {quantity} {unit}")
    return cursor.lastrowid

def get_daily_work_logs(employee=None, days=7, limit=100):
    where = []
    params = []
    if employee and employee not in ("همه کارکنان", "مالک", ""):
        variants = employee_name_variants(employee)
        placeholders = ",".join("?" for _ in variants)
        where.append(f"employee IN ({placeholders})")
        params.extend(variants)
    where.append("work_date >= date('now', ?)")
    params.append(f"-{int(days)} days")
    sql = f"""
        SELECT id, employee, work_type, quantity, unit, notes, work_date, created_at
        FROM employee_daily_logs
        WHERE {" AND ".join(where)}
        ORDER BY work_date DESC, id DESC
        LIMIT ?
    """
    params.append(int(limit))
    cursor.execute(sql, tuple(params))
    return cursor.fetchall()

def get_personal_dashboard(employee):
    """داده‌های کارتابل شخصی یک کارمند واقعی."""
    role = normalize_employee_role(employee)
    today = datetime.now().strftime("%Y-%m-%d")
    variants = employee_name_variants(employee)

    # وظایف
    open_tasks = get_open_manager_tasks(employee=role, limit=30)
    # اگر با نام واقعی هم وظیفه‌ای باشد
    if employee != role:
        extra = get_open_manager_tasks(employee=employee, limit=20)
        seen = {t[0] for t in open_tasks}
        for t in extra:
            if t[0] not in seen:
                open_tasks.append(t)

    # هشدارهای باز مرتبط
    cursor.execute("""
        SELECT id, alert_type, severity, title, details, created_at
        FROM manager_alerts
        WHERE acknowledged = 0 AND (related_employee = ? OR related_employee = ? OR related_employee = '')
        ORDER BY CASE severity WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, id DESC
        LIMIT 15
    """, (role, employee))
    alerts = cursor.fetchall()

    # کار روزانه امروز
    placeholders = ",".join("?" for _ in variants)
    cursor.execute(f"""
        SELECT work_type, quantity, unit, notes, created_at
        FROM employee_daily_logs
        WHERE employee IN ({placeholders}) AND work_date = ?
        ORDER BY id DESC
    """, (*variants, today))
    today_logs = cursor.fetchall()

    # فعالیت‌های امروز
    activities = 0
    for name in variants:
        cursor.execute(
            "SELECT COUNT(*) FROM employee_activity WHERE employee=? AND activity_date LIKE ?",
            (name, today + "%"),
        )
        activities += int(cursor.fetchone()[0] or 0)

    # کار واقعی سیستم امروز
    real_work = {}
    if role == "کارمند فروشگاه":
        cursor.execute("SELECT COUNT(*), COALESCE(SUM(total),0) FROM sales WHERE substr(sale_date,1,10)=?", (today,))
        cnt, total = cursor.fetchone()
        real_work = {"فروش‌ها": int(cnt or 0), "مبلغ فروش": float(total or 0)}
    elif role == "کارمند انبار":
        cursor.execute("SELECT COUNT(*) FROM products WHERE quantity <= 5")
        real_work = {"کالای کم‌موجودی": int(cursor.fetchone()[0] or 0)}
        cursor.execute("SELECT COUNT(*) FROM products WHERE quantity < 0")
        real_work["موجودی منفی"] = int(cursor.fetchone()[0] or 0)
    elif role == "کارمند حسابداری":
        cursor.execute("SELECT COUNT(*) FROM accounting WHERE substr(entry_date,1,10)=?", (today,))
        real_work = {"ثبت‌های حسابداری امروز": int(cursor.fetchone()[0] or 0)}
    elif role == "کارمند کارپرداز":
        cursor.execute("SELECT COUNT(*) FROM purchase_requests WHERE status='در انتظار' OR approval_status LIKE '%انتظار%'")
        real_work = {"درخواست خرید باز": int(cursor.fetchone()[0] or 0)}

    # امتیاز از get_employee_performance
    score = 100
    try:
        for item in get_employee_performance():
            if item["employee"] == role:
                score = item["score"]
                break
    except Exception:
        pass

    return {
        "employee": employee,
        "role": role,
        "display": EMPLOYEE_DISPLAY.get(role, employee),
        "open_tasks": open_tasks,
        "alerts": alerts,
        "today_logs": today_logs,
        "activities_today": activities,
        "real_work": real_work,
        "score": score,
    }

def get_owner_performance_report(days=7):
    """گزارش عملکرد کارکنان برای مالک."""
    lines = []
    lines.append(f"📊 گزارش عملکرد کارکنان — {days} روز اخیر")
    lines.append(f"تاریخ تهیه: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    lines.append("=" * 50)

    try:
        perf = get_employee_performance()
    except Exception as e:
        return f"خطا در محاسبه عملکرد: {e}"

    for item in perf:
        role = item["employee"]
        display = EMPLOYEE_DISPLAY.get(role, role)
        lines.append(f"\n👤 {display}")
        lines.append(f"   امتیاز: {item['score']:.0f}/100")
        lines.append(f"   فعالیت امروز: {item['activities']} | وظایف باز: {item['open_tasks']} | انجام‌شده امروز: {item['done_today']}")
        lines.append(f"   مسائل باز: {item['open_issues']}")

        # کار روزانه ثبت‌شده
        logs = get_daily_work_logs(role, days=days, limit=20)
        if logs:
            lines.append(f"   کار روزانه ثبت‌شده ({len(logs)} مورد):")
            for lid, emp, wtype, qty, unit, notes, wdate, created in logs[:5]:
                lines.append(f"     • {wdate}: {wtype} — {qty:g} {unit}")
        else:
            lines.append("   کار روزانه: هنوز ثبت نشده")

        # فروش/خرید واقعی
        today = datetime.now().strftime("%Y-%m-%d")
        if role == "کارمند فروشگاه":
            cursor.execute(
                "SELECT COUNT(*), COALESCE(SUM(total),0) FROM sales WHERE substr(sale_date,1,10) >= date('now', ?)",
                (f"-{days} days",),
            )
            cnt, total = cursor.fetchone()
            lines.append(f"   فروش {days} روز: {int(cnt or 0)} فاکتور | {float(total or 0):,.0f} ریال")
        elif role == "کارمند کارپرداز":
            cursor.execute(
                "SELECT COUNT(*) FROM purchases WHERE substr(purchase_date,1,10) >= date('now', ?)",
                (f"-{days} days",),
            )
            lines.append(f"   خریدهای ثبت‌شده {days} روز: {int(cursor.fetchone()[0] or 0)}")
        elif role == "کارمند حسابداری":
            cursor.execute(
                "SELECT COUNT(*) FROM accounting WHERE substr(entry_date,1,10) >= date('now', ?)",
                (f"-{days} days",),
            )
            lines.append(f"   ثبت‌های حسابداری {days} روز: {int(cursor.fetchone()[0] or 0)}")

    lines.append("\n" + "=" * 50)
    lines.append("هشدارهای باز سیستم:")
    try:
        rows = get_open_manager_alerts(10)
        if not rows:
            lines.append("  موردی نیست.")
        else:
            for r in rows:
                # id, alert_type, severity, title, details, related_employee, created_at
                lines.append(f"  [{r[2]}] {r[3]} ({r[5] or 'سیستم'})")
    except Exception:
        lines.append("  خطا در خواندن هشدارها")

    return "\n".join(lines)



cursor.execute("""
CREATE TABLE IF NOT EXISTS customers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    phone TEXT,
    address TEXT,
    city TEXT,
    region TEXT,
    latitude REAL,
    longitude REAL,
    notes TEXT,
    created_at TEXT
)
""")

# =========================================================
# حسابداری
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS accounting (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    entry_type TEXT NOT NULL,
    category TEXT NOT NULL,
    amount REAL NOT NULL DEFAULT 0,
    description TEXT,
    related_sale_id INTEGER,
    entry_date TEXT
)
""")

# کارمند ثبت‌کننده تراکنش‌های حسابداری
cursor.execute("PRAGMA table_info(accounting)")
accounting_columns = [row[1] for row in cursor.fetchall()]
if "employee" not in accounting_columns:
    cursor.execute("ALTER TABLE accounting ADD COLUMN employee TEXT")


# =========================================================
# حساب های پایه حسابداری
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS accounts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE NOT NULL,
    account_type TEXT NOT NULL,
    balance REAL DEFAULT 0
)
""")

# ماهیت هر حساب: بدهکار (debit) یعنی بدهکار شدن آن را افزایش می‌دهد
# مثل دارایی‌ها و هزینه‌ها؛ بستانکار (credit) یعنی بستانکار شدن آن را
# افزایش می‌دهد، مثل درآمد، سرمایه و بدهی‌ها.
cursor.execute("PRAGMA table_info(accounts)")
accounts_columns = [row[1] for row in cursor.fetchall()]
if "normal_side" not in accounts_columns:
    cursor.execute("ALTER TABLE accounts ADD COLUMN normal_side TEXT DEFAULT 'debit'")

base_accounts = [
    ("صندوق", "دارایی", "debit"),
    ("بانک", "دارایی", "debit"),
    ("موجودی کالا", "دارایی", "debit"),
    ("تجهیزات", "دارایی", "debit"),
    ("مشتریان", "اشخاص", "debit"),
    ("تامین کنندگان", "اشخاص", "credit"),
    ("فروش کالا", "درآمد", "credit"),
    ("خرید کالا", "هزینه", "debit"),
    ("بهای تمام‌شده کالای فروش‌رفته", "هزینه", "debit"),
    ("حمل و نقل", "هزینه", "debit"),
    ("هزینه متفرقه", "هزینه", "debit"),
    ("حقوق کارکنان", "هزینه", "debit"),
    ("اجاره", "هزینه", "debit"),
    ("آب و برق", "هزینه", "debit"),
    ("تبلیغات", "هزینه", "debit"),
    ("تعمیرات", "هزینه", "debit"),
    ("مالیات", "هزینه", "debit"),
    ("عمومی", "هزینه", "debit"),
    ("سایر", "هزینه", "debit"),
    ("سرمایه", "سرمایه", "credit"),
    ("سود و زیان", "کنترلی", "credit"),
]

for acc_name, acc_type, acc_side in base_accounts:
    cursor.execute(
        "INSERT OR IGNORE INTO accounts(name, account_type, balance, normal_side) VALUES(?,?,0,?)",
        (acc_name, acc_type, acc_side)
    )
    # برای حساب‌هایی که از قبل با مقدار پیش‌فرض ساخته شده بودند، ماهیت درست را ثبت کن
    cursor.execute(
        "UPDATE accounts SET normal_side=? WHERE name=? AND (normal_side IS NULL OR normal_side='')",
        (acc_side, acc_name)
    )

conn.commit()

# نگاشت دسته‌های فرم ثبت هزینه به نام حساب مربوطه در چارت حساب‌ها
EXPENSE_CATEGORY_TO_ACCOUNT = {
    "عمومی": "عمومی",
    "اجاره": "اجاره",
    "حقوق": "حقوق کارکنان",
    "آب و برق": "آب و برق",
    "حمل و نقل": "حمل و نقل",
    "خرید کالا": "خرید کالا",
    "تبلیغات": "تبلیغات",
    "تعمیرات": "تعمیرات",
    "مالیات": "مالیات",
    "سایر": "سایر",
}

# =========================================================
# دفتر کل دوطرفه (Ledger)
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS ledger_entries (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    txn_id TEXT NOT NULL,
    account_id INTEGER NOT NULL,
    account_name TEXT NOT NULL,
    debit REAL DEFAULT 0,
    credit REAL DEFAULT 0,
    description TEXT,
    ref_type TEXT,
    ref_id INTEGER,
    entry_date TEXT,
    employee TEXT
)
""")
conn.commit()


def get_account_row(account_name):
    cursor.execute(
        "SELECT id, normal_side FROM accounts WHERE name=?",
        (account_name,)
    )
    return cursor.fetchone()


def post_journal(lines, ref_type=None, ref_id=None, description='', entry_date=None, employee=None, commit=True):
    """ثبت سند دوطرفه؛ commit اختیاری است تا عملیات چندمرحله‌ای اتمیک بماند."""
    entry_date = entry_date or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    employee = employee or get_active_employee()
    clean=[]
    for line in lines:
        if len(line) != 3:
            raise ValueError('ساختار سند حسابداری نامعتبر است.')
        name,debit,credit=line
        debit=round(float(debit or 0),2); credit=round(float(credit or 0),2)
        if debit < 0 or credit < 0:
            raise ValueError('مبلغ بدهکار/بستانکار نمی‌تواند منفی باشد.')
        if debit and credit:
            raise ValueError(f'حساب «{name}» نمی‌تواند هم‌زمان بدهکار و بستانکار باشد.')
        if debit or credit:
            clean.append((name,debit,credit))
    total_debit=round(sum(x[1] for x in clean),2)
    total_credit=round(sum(x[2] for x in clean),2)
    if not clean or total_debit != total_credit:
        raise ValueError(f'سند حسابداری نامتوازن است (بدهکار: {total_debit:,.2f} / بستانکار: {total_credit:,.2f})')
    txn_id=f"{ref_type or 'manual'}-{ref_id or 0}-{datetime.now().strftime('%Y%m%d%H%M%S%f')}"
    for account_name,debit,credit in clean:
        row=get_account_row(account_name)
        if row is None:
            raise ValueError(f'حساب «{account_name}» در چارت حساب‌ها یافت نشد.')
        account_id,normal_side=row
        delta=(debit-credit) if normal_side=='debit' else (credit-debit)
        cursor.execute('UPDATE accounts SET balance=COALESCE(balance,0)+? WHERE id=?',(delta,account_id))
        cursor.execute("""INSERT INTO ledger_entries
            (txn_id,account_id,account_name,debit,credit,description,ref_type,ref_id,entry_date,employee)
            VALUES (?,?,?,?,?,?,?,?,?,?)""",
            (txn_id,account_id,account_name,debit,credit,description,ref_type,ref_id,entry_date,employee))
    if commit:
        conn.commit()
    return txn_id


def post_simple(debit_account, credit_account, amount, description='', ref_type=None, ref_id=None, entry_date=None, employee=None, commit=True):
    amount=round(float(amount or 0),2)
    if amount <= 0:
        raise ValueError('مبلغ سند باید بیشتر از صفر باشد.')
    return post_journal([(debit_account,amount,0),(credit_account,0,amount)],
                        ref_type=ref_type,ref_id=ref_id,description=description,
                        entry_date=entry_date,employee=employee,commit=commit)

def get_product_buy_price(product_id):
    cursor.execute("SELECT COALESCE(avg_buy_price,buy_price,0) FROM products WHERE id=?",(product_id,))
    row=cursor.fetchone()
    return float(row[0] or 0) if row else 0.0


def get_product_buy_price(product_id):
    cursor.execute("SELECT buy_price FROM products WHERE id=?", (product_id,))
    row = cursor.fetchone()
    return float(row[0]) if row and row[0] else 0.0


# =========================================================
# فعالیت کارکنان
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_activity (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    action TEXT NOT NULL,
    details TEXT,
    activity_date TEXT
)
""")

# ثبت خطاها و هشدارهای کارکنان برای یادگیری مدیریتی
cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_issues (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    issue_type TEXT NOT NULL,
    description TEXT NOT NULL,
    severity TEXT DEFAULT 'medium',
    resolved INTEGER DEFAULT 0,
    created_at TEXT
)
""")

# امتیازهای دوره‌ای کارکنان
cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_reviews (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    review_date TEXT NOT NULL,
    score REAL NOT NULL DEFAULT 0,
    summary TEXT,
    ai_comment TEXT
)
""")

# برنامه‌های آموزشی و مسیر بهبود کارکنان
cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_training (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    skill TEXT NOT NULL,
    current_level TEXT DEFAULT 'needs_improvement',
    training_goal TEXT NOT NULL,
    actions TEXT NOT NULL,
    success_metric TEXT NOT NULL,
    status TEXT DEFAULT 'open',
    created_at TEXT NOT NULL,
    reviewed_at TEXT
)
""")

# روند پیشرفت کارکنان برای مقایسه یادگیری در طول زمان
cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_learning_progress (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    review_date TEXT NOT NULL,
    score REAL NOT NULL DEFAULT 0,
    open_issues INTEGER DEFAULT 0,
    completed_tasks INTEGER DEFAULT 0,
    note TEXT,
    created_at TEXT NOT NULL
)
""")

# ثبت کار روزانه واقعی کارکنان
cursor.execute("""
CREATE TABLE IF NOT EXISTS employee_daily_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    employee TEXT NOT NULL,
    work_type TEXT NOT NULL,
    quantity REAL DEFAULT 1,
    unit TEXT DEFAULT 'مورد',
    notes TEXT,
    work_date TEXT NOT NULL,
    created_at TEXT NOT NULL
)
""")
try:
    cursor.execute("CREATE INDEX IF NOT EXISTS idx_daily_logs_emp_date ON employee_daily_logs(employee, work_date)")
except Exception:
    pass

# =========================================================
# مغز مدیریتی هوش مصنوعی
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS ai_profile (
    id INTEGER PRIMARY KEY CHECK (id = 1),
    owner_name TEXT NOT NULL DEFAULT 'مالک برنامه',
    role TEXT NOT NULL DEFAULT 'مدیر ارشد و ناظر کل سیستم',
    mission TEXT NOT NULL DEFAULT 'کمک به مالک، نظارت بر کارکنان و تحلیل عملکرد فروشگاه',
    rules TEXT DEFAULT '',
    updated_at TEXT
)
""")

cursor.execute("""
CREATE TABLE IF NOT EXISTS ai_learning (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    topic TEXT NOT NULL,
    lesson TEXT NOT NULL,
    source TEXT DEFAULT 'manager',
    confidence REAL DEFAULT 1.0,
    created_at TEXT
)
""")

cursor.execute("""
CREATE TABLE IF NOT EXISTS ai_manager_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    report_date TEXT NOT NULL,
    summary TEXT NOT NULL,
    ai_advice TEXT,
    created_at TEXT
)
""")

cursor.execute("""
CREATE TABLE IF NOT EXISTS ai_email_insights (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email_account TEXT,
    sender TEXT,
    subject TEXT,
    insight TEXT NOT NULL,
    importance TEXT DEFAULT 'medium',
    created_at TEXT
)
""")

# پیشنهادهای ارتقای برنامه که AI تولید می‌کند و فقط با تأیید مالک قابل اجراست
cursor.execute("""
CREATE TABLE IF NOT EXISTS ai_code_suggestions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    suggestion TEXT NOT NULL,
    status TEXT DEFAULT 'pending',
    created_at TEXT,
    reviewed_at TEXT,
    owner_note TEXT
)
""")
conn.commit()

# =========================================================
# مرکز وظایف و پیگیری کار کارکنان
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS manager_tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    description TEXT,
    assigned_employee TEXT NOT NULL,
    source TEXT DEFAULT 'manager',
    priority TEXT DEFAULT 'medium',
    status TEXT DEFAULT 'open',
    due_date TEXT,
    created_at TEXT NOT NULL,
    completed_at TEXT,
    manager_note TEXT
)
""")

# ستون‌های اجرای واقعی وظایف کارکنان
try:
    cursor.execute("PRAGMA table_info(manager_tasks)")
    _task_cols = {r[1] for r in cursor.fetchall()}
    for _col, _definition in [
        ("started_at", "TEXT"),
        ("execution_result", "TEXT"),
        ("execution_mode", "TEXT DEFAULT 'manual'"),
        ("last_error", "TEXT")
    ]:
        if _col not in _task_cols:
            cursor.execute(f"ALTER TABLE manager_tasks ADD COLUMN {_col} {_definition}")
    conn.commit()
except Exception:
    pass

cursor.execute("SELECT COUNT(*) FROM ai_profile WHERE id = 1")
if cursor.fetchone()[0] == 0:
    cursor.execute("""
        INSERT INTO ai_profile (id, owner_name, role, mission, rules, updated_at)
        VALUES (1, ?, ?, ?, ?, ?)
    """, (
        CREATOR_NAME,
        'خالق و مالک اصلی سیستم',
        'نظارت بر انبار، فروشگاه، حسابداری و کارکنان و کمک به مالک در تصمیم‌گیری',
        'مالک سیستم بالاترین سطح اختیار را دارد. اطلاعات را حدس نزن. تصمیم‌های حساس را بدون تأیید مالک اجرا نکن.',
        datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    ))

conn.commit()

# =========================================================
# نگهبان هوشمند و هشدارهای خودکار مدیر
# =========================================================

cursor.execute("""
CREATE TABLE IF NOT EXISTS manager_alerts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    alert_type TEXT NOT NULL,
    severity TEXT DEFAULT 'medium',
    title TEXT NOT NULL,
    details TEXT,
    related_employee TEXT,
    source TEXT DEFAULT 'auto_monitor',
    created_at TEXT NOT NULL,
    acknowledged INTEGER DEFAULT 0
)
""")
conn.commit()

def create_manager_alert(alert_type, title, details='', severity='medium', employee=''):
    cursor.execute("""
        SELECT id FROM manager_alerts
        WHERE alert_type = ? AND title = ? AND acknowledged = 0
        ORDER BY id DESC LIMIT 1
    """, (str(alert_type), str(title)))
    if cursor.fetchone():
        return False
    cursor.execute("""
        INSERT INTO manager_alerts
        (alert_type, severity, title, details, related_employee, created_at)
        VALUES (?, ?, ?, ?, ?, ?)
    """, (str(alert_type), str(severity), str(title), str(details)[:2500], str(employee or ''), datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
    conn.commit()
    return True

def get_open_manager_alerts(limit=50):
    cursor.execute("""
        SELECT id, alert_type, severity, title, details, related_employee, created_at
        FROM manager_alerts WHERE acknowledged = 0
        ORDER BY CASE severity WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, id DESC LIMIT ?
    """, (int(limit),))
    return cursor.fetchall()

def acknowledge_manager_alert(alert_id):
    cursor.execute("UPDATE manager_alerts SET acknowledged = 1 WHERE id = ?", (int(alert_id),))
    conn.commit()

def run_smart_monitoring():
    """نظارت هوشمند و خودکار بر عملکرد کارکنان و وضعیت فروشگاه"""
    created = 0
    today = datetime.now().strftime('%Y-%m-%d')

    # ۱. موجودی منفی
    cursor.execute("SELECT name, quantity FROM products WHERE quantity < 0 LIMIT 20")
    for name, quantity in cursor.fetchall():
        if create_manager_alert('negative_stock', f'موجودی منفی: {name}', f'موجودی {name} برابر {quantity} است.', 'high', 'کارمند انبار'):
            create_manager_task(f'بررسی موجودی منفی: {name}', f'موجودی فعلی: {quantity}. علت و اصلاح ثبت شود.', 'کارمند انبار', source='auto_monitor', priority='high')
            record_employee_issue('کارمند انبار', 'موجودی منفی', f'{name}: {quantity}', 'high')
            created += 1

    # ۲. اختلاف فروش با درآمد حسابداری
    cursor.execute("SELECT COALESCE(SUM(total),0) FROM sales WHERE substr(sale_date,1,10)=?", (today,))
    sales_total = float(cursor.fetchone()[0] or 0)
    cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='income' AND substr(entry_date,1,10)=?", (today,))
    income_total = float(cursor.fetchone()[0] or 0)
    if abs(sales_total - income_total) > 0.01:
        if create_manager_alert('sales_accounting_mismatch', 'اختلاف فروش با درآمد حسابداری', f'فروش امروز: {sales_total:,.0f} | درآمد حسابداری: {income_total:,.0f}', 'high', 'کارمند حسابداری'):
            create_manager_task('بررسی اختلاف فروش و حسابداری', f'فروش امروز {sales_total:,.0f} و درآمد ثبت‌شده {income_total:,.0f}.', 'کارمند حسابداری', source='auto_monitor', priority='high')
            record_employee_issue('کارمند حسابداری', 'اختلاف مالی', f'اختلاف {abs(sales_total-income_total):,.0f} ریال', 'high')
            created += 1

    # ۳. کمبود موجودی
    cursor.execute("SELECT name, quantity, unit FROM products WHERE quantity <= 5 AND quantity >= 0 ORDER BY quantity LIMIT 15")
    for name, quantity, unit in cursor.fetchall():
        if create_manager_alert('low_stock', f'کمبود موجودی: {name}', f'{name}: {quantity} {unit}', 'medium', 'کارمند انبار'):
            create_manager_task(f'کمبود موجودی: {name}', f'موجودی فعلی {name}: {quantity} {unit}. موجودی را بررسی و در صورت نیاز درخواست خرید ایجاد کن.', 'کارمند انبار', source='auto_monitor', priority='medium')
            created += 1

    # ۴. فروش بدون مشتری (مشکوک)
    cursor.execute("""
        SELECT COUNT(*) FROM sales
        WHERE substr(sale_date,1,10)=? AND (customer_id IS NULL OR customer_id=0)
    """, (today,))
    no_customer_sales = int(cursor.fetchone()[0] or 0)
    if no_customer_sales >= 5:
        if create_manager_alert('sales_no_customer', 'فروش‌های بدون مشتری', f'{no_customer_sales} فروش امروز بدون ثبت مشتری انجام شده.', 'medium', 'کارمند فروشگاه'):
            create_manager_task('بررسی فروش‌های بدون مشتری', f'امروز {no_customer_sales} فروش بدون مشتری ثبت شده. علت بررسی شود.', 'کارمند فروشگاه', source='auto_monitor', priority='medium')
            created += 1

    # ۵. هزینه بیشتر از درآمد امروز
    cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='expense' AND substr(entry_date,1,10)=?", (today,))
    expense_total = float(cursor.fetchone()[0] or 0)
    if expense_total > income_total and expense_total > 0:
        if create_manager_alert('expense_over_income', 'هزینه بیشتر از درآمد', f'درآمد امروز: {income_total:,.0f} | هزینه: {expense_total:,.0f}', 'high', 'کارمند حسابداری'):
            create_manager_task('بررسی هزینه‌های امروز', f'هزینه امروز از درآمد بیشتر است. جزئیات بررسی شود.', 'کارمند حسابداری', source='auto_monitor', priority='high')
            created += 1

    # ۶. درخواست خرید معوق (بیش از ۲ روز در انتظار)
    cursor.execute("""
        SELECT COUNT(*) FROM purchase_requests
        WHERE status='در انتظار' AND date(request_date) <= date('now', '-2 day')
    """)
    old_requests = int(cursor.fetchone()[0] or 0)
    if old_requests > 0:
        if create_manager_alert('old_purchase_requests', 'درخواست خرید معوق', f'{old_requests} درخواست خرید بیش از ۲ روز در انتظار مانده.', 'medium', 'کارمند کارپرداز'):
            create_manager_task('پیگیری درخواست‌های خرید معوق', f'{old_requests} درخواست خرید قدیمی نیاز به پیگیری دارد.', 'کارمند کارپرداز', source='auto_monitor', priority='medium')
            created += 1

    # ۷. ارزیابی عملکرد کارکنان و ایجاد وظیفه در صورت افت
    try:
        performance = get_employee_performance()
        for item in performance:
            emp = item['employee']
            score = item['score']
            open_issues = item['open_issues']

            if score < 70:
                title = f'افت عملکرد: {emp}'
                if create_manager_alert('low_performance', title, f'امتیاز فعلی: {score:.0f}/100 | هشدار باز: {open_issues}', 'high', emp):
                    create_manager_task(
                        f'بهبود عملکرد {emp}',
                        f'امتیاز به {score:.0f} رسیده. هشدارهای باز: {open_issues}. برنامه بهبود اجرا شود.',
                        emp, source='auto_monitor', priority='high'
                    )
                    created += 1
            elif open_issues >= 3:
                title = f'هشدارهای باز زیاد: {emp}'
                if create_manager_alert('many_open_issues', title, f'{open_issues} هشدار باز برای این کارمند وجود دارد.', 'medium', emp):
                    create_manager_task(
                        f'رفع هشدارهای باز {emp}',
                        f'{open_issues} مورد باز نیاز به رسیدگی فوری دارد.',
                        emp, source='auto_monitor', priority='medium'
                    )
                    created += 1
    except Exception:
        pass

    return created

def get_alert_summary(limit=10):
    rows = get_open_manager_alerts(limit)
    if not rows:
        return 'هشدار باز وجود ندارد.'
    return '\n'.join(f'[{severity}] {title} | {employee or "سیستم"} | {created_at}\n{details}' for _,_,severity,title,details,employee,created_at in rows)

# بررسی اولیه هنگام اجرای برنامه
try:
    run_smart_monitoring()
except Exception:
    pass

# =========================================================
# ایمیل
# =========================================================

def _load_email_config():
    try:
        if os.path.exists(EMAIL_CONFIG_FILE):
            with open(EMAIL_CONFIG_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
    except Exception:
        pass
    return {}


def _save_email_config(config):
    safe = dict(config)
    safe.pop('password', None)
    with open(EMAIL_CONFIG_FILE, 'w', encoding='utf-8') as f:
        json.dump(safe, f, ensure_ascii=False, indent=2)


class _DATA_BLOB(ctypes.Structure):
    _fields_ = [('cbData', wintypes.DWORD), ('pbData', ctypes.POINTER(ctypes.c_ubyte))]


def _dpapi_protect(text):
    if os.name != 'nt':
        return None
    crypt32 = ctypes.windll.crypt32
    kernel32 = ctypes.windll.kernel32
    raw = text.encode('utf-8')
    buf = (ctypes.c_ubyte * len(raw))(*raw)
    blob_in = _DATA_BLOB(len(raw), buf)
    blob_out = _DATA_BLOB()
    if not crypt32.CryptProtectData(ctypes.byref(blob_in), None, None, None, None, 0, ctypes.byref(blob_out)):
        return None
    try:
        data = ctypes.string_at(blob_out.pbData, blob_out.cbData)
        return base64.b64encode(data).decode('ascii')
    finally:
        kernel32.LocalFree(blob_out.pbData)


def _dpapi_unprotect(encoded):
    if os.name != 'nt' or not encoded:
        return ''
    try:
        crypt32 = ctypes.windll.crypt32
        kernel32 = ctypes.windll.kernel32
        raw = base64.b64decode(encoded.encode('ascii'))
        buf = (ctypes.c_ubyte * len(raw))(*raw)
        blob_in = _DATA_BLOB(len(raw), buf)
        blob_out = _DATA_BLOB()
        if not crypt32.CryptUnprotectData(ctypes.byref(blob_in), None, None, None, None, 0, ctypes.byref(blob_out)):
            return ''
        try:
            return ctypes.string_at(blob_out.pbData, blob_out.cbData).decode('utf-8', errors='replace')
        finally:
            kernel32.LocalFree(blob_out.pbData)
    except Exception:
        return ''


def _get_email_password(email_address):
    try:
        import keyring
        value = keyring.get_password(EMAIL_CREDENTIAL_SERVICE, email_address)
        if value:
            return value
    except Exception:
        pass
    try:
        if os.path.exists(EMAIL_SECRET_FILE):
            with open(EMAIL_SECRET_FILE, 'r', encoding='utf-8') as f:
                data = json.load(f)
            item = data.get(email_address, '')
            return _dpapi_unprotect(item)
    except Exception:
        pass
    return ''


def _set_email_password(email_address, password):
    try:
        import keyring
        keyring.set_password(EMAIL_CREDENTIAL_SERVICE, email_address, password)
        return True
    except Exception:
        pass
    try:
        encoded = _dpapi_protect(password)
        if not encoded:
            return False
        data = {}
        if os.path.exists(EMAIL_SECRET_FILE):
            try:
                with open(EMAIL_SECRET_FILE, 'r', encoding='utf-8') as f:
                    data = json.load(f)
            except Exception:
                data = {}
        data[email_address] = encoded
        with open(EMAIL_SECRET_FILE, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        return True
    except Exception:
        return False


def _delete_email_password(email_address):
    try:
        import keyring
        try:
            keyring.delete_password(EMAIL_CREDENTIAL_SERVICE, email_address)
        except Exception:
            pass
    except Exception:
        pass
    try:
        if os.path.exists(EMAIL_SECRET_FILE):
            with open(EMAIL_SECRET_FILE, 'r', encoding='utf-8') as f:
                data = json.load(f)
            data.pop(email_address, None)
            with open(EMAIL_SECRET_FILE, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception:
        pass


def _decode_email_header(value):
    if not value:
        return ''
    parts = []
    for chunk, enc in decode_header(value):
        if isinstance(chunk, bytes):
            try:
                parts.append(chunk.decode(enc or 'utf-8', errors='replace'))
            except Exception:
                parts.append(chunk.decode('utf-8', errors='replace'))
        else:
            parts.append(chunk)
    return ''.join(parts)


def _extract_email_body(msg):
    plain = []
    html_parts = []
    if msg.is_multipart():
        for part in msg.walk():
            if part.get_content_disposition() == 'attachment':
                continue
            ctype = part.get_content_type()
            try:
                payload = part.get_payload(decode=True)
                if not payload:
                    continue
                charset = part.get_content_charset() or 'utf-8'
                text = payload.decode(charset, errors='replace')
            except Exception:
                continue
            if ctype == 'text/plain':
                plain.append(text)
            elif ctype == 'text/html':
                html_parts.append(re.sub(r'<[^>]+>', ' ', text))
    else:
        try:
            payload = msg.get_payload(decode=True)
            if payload:
                charset = msg.get_content_charset() or 'utf-8'
                text = payload.decode(charset, errors='replace')
                if msg.get_content_type() == 'text/html':
                    html_parts.append(re.sub(r'<[^>]+>', ' ', text))
                else:
                    plain.append(text)
        except Exception:
            pass
    text = '\n'.join(plain).strip() or '\n'.join(html_parts).strip()
    text = re.sub(r'\s+\n', '\n', text)
    return text.strip()


def _imap_connect(config, password):
    host = config.get('imap_host', '').strip()
    port = int(config.get('imap_port', 993))
    use_ssl = bool(config.get('imap_ssl', True))
    if use_ssl:
        mail = imaplib.IMAP4_SSL(host, port)
    else:
        mail = imaplib.IMAP4(host, port)
        mail.starttls(ssl_context=ssl.create_default_context())
    mail.login(config.get('email', '').strip(), password)
    return mail


def _smtp_send(config, password, to_addr, subject, body, cc='', bcc=''):
    host = config.get('smtp_host', '').strip()
    port = int(config.get('smtp_port', 465))
    msg = EmailMessage()
    msg['From'] = config.get('email', '').strip()
    msg['To'] = to_addr.strip()
    if cc.strip():
        msg['Cc'] = cc.strip()
    msg['Subject'] = subject
    msg.set_content(body)
    recipients = [x.strip() for x in (to_addr + ',' + cc + ',' + bcc).split(',') if x.strip()]
    use_ssl = bool(config.get('smtp_ssl', True))
    if use_ssl:
        with smtplib.SMTP_SSL(host, port, context=ssl.create_default_context()) as server:
            server.login(config.get('email', '').strip(), password)
            server.send_message(msg, to_addrs=recipients)
    else:
        with smtplib.SMTP(host, port, timeout=30) as server:
            server.ehlo()
            server.starttls(context=ssl.create_default_context())
            server.ehlo()
            server.login(config.get('email', '').strip(), password)
            server.send_message(msg, to_addrs=recipients)


def open_email_window():
    email_window = tk.Toplevel(window)
    email_window.title('✉️ ایمیل هوشمند')
    email_window.geometry('1180x760')

    cfg = _load_email_config()

    presets = {
        'Gmail':   {'imap_host':'imap.gmail.com','imap_port':993,'imap_ssl':True,'smtp_host':'smtp.gmail.com','smtp_port':465,'smtp_ssl':True},
        'Outlook': {'imap_host':'outlook.office365.com','imap_port':993,'imap_ssl':True,'smtp_host':'smtp.office365.com','smtp_port':587,'smtp_ssl':False},
        'Yahoo':   {'imap_host':'imap.mail.yahoo.com','imap_port':993,'imap_ssl':True,'smtp_host':'smtp.mail.yahoo.com','smtp_port':465,'smtp_ssl':True},
        'Hostinger': {'imap_host':'imap.hostinger.com','imap_port':993,'imap_ssl':True,'smtp_host':'smtp.hostinger.com','smtp_port':465,'smtp_ssl':True},
        'سایر':    {}
    }

    top = tk.Frame(email_window)
    top.pack(fill=tk.X, padx=10, pady=8)

    tk.Label(top, text='ارائه‌دهنده:').grid(row=0, column=0, padx=5, pady=4)
    provider_var = tk.StringVar(value=cfg.get('provider','Gmail'))
    provider_combo = ttk.Combobox(top, textvariable=provider_var, values=list(presets.keys()), state='readonly', width=14)
    provider_combo.grid(row=0, column=1, padx=5)

    tk.Label(top, text='ایمیل:').grid(row=0, column=2, padx=5)
    email_var = tk.StringVar(value=cfg.get('email',''))
    email_entry = tk.Entry(top, textvariable=email_var, width=30)
    email_entry.grid(row=0, column=3, padx=5)

    tk.Label(top, text='رمز/رمز برنامه:').grid(row=0, column=4, padx=5)
    password_var = tk.StringVar(value='')
    password_entry = tk.Entry(top, textvariable=password_var, show='*', width=22)
    password_entry.grid(row=0, column=5, padx=5)

    status_var = tk.StringVar(value='آماده')
    tk.Label(email_window, textvariable=status_var, anchor='w').pack(fill=tk.X, padx=12)

    server_frame = tk.LabelFrame(email_window, text='تنظیمات اتصال')
    server_frame.pack(fill=tk.X, padx=10, pady=5)

    vars_map = {}
    fields = [
        ('imap_host','IMAP'),('imap_port','پورت IMAP'),('smtp_host','SMTP'),('smtp_port','پورت SMTP')
    ]
    for i,(key,label) in enumerate(fields):
        tk.Label(server_frame, text=label).grid(row=0, column=i*2, padx=5, pady=4)
        v = tk.StringVar(value=str(cfg.get(key, presets.get(provider_var.get(),{}).get(key,''))))
        vars_map[key] = v
        tk.Entry(server_frame, textvariable=v, width=22).grid(row=0, column=i*2+1, padx=5, pady=4)

    def apply_preset(*_):
        preset = presets.get(provider_var.get(), {})
        for key, var in vars_map.items():
            if key in preset:
                var.set(str(preset[key]))

    provider_combo.bind('<<ComboboxSelected>>', apply_preset)
    if not cfg.get('imap_host'):
        apply_preset()

    def current_config():
        return {
            'provider': provider_var.get(),
            'email': email_var.get().strip(),
            'imap_host': vars_map['imap_host'].get().strip(),
            'imap_port': int(vars_map['imap_port'].get() or 993),
            'imap_ssl': True,
            'smtp_host': vars_map['smtp_host'].get().strip(),
            'smtp_port': int(vars_map['smtp_port'].get() or 465),
            'smtp_ssl': provider_var.get() != 'Outlook'
        }

    def save_settings():
        try:
            c = current_config()
            if not c['email']:
                raise ValueError('ایمیل را وارد کنید.')
            _save_email_config(c)
            pwd = password_var.get()
            if pwd and not _set_email_password(c['email'], pwd):
                messagebox.showwarning('هشدار', 'ذخیره امن رمز ممکن نشد. بسته keyring را نصب کنید.')
            elif not pwd and not _get_email_password(c['email']):
                messagebox.showwarning('هشدار', 'رمز/رمز برنامه ذخیره نشده است.')
            status_var.set('تنظیمات ذخیره شد.')
        except Exception as e:
            messagebox.showerror('خطا', str(e))

    def test_connection():
        def worker():
            try:
                c = current_config()
                pwd = password_var.get() or _get_email_password(c['email'])
                if not pwd:
                    raise ValueError('رمز/رمز برنامه را وارد کنید.')
                m = _imap_connect(c, pwd)
                m.select('INBOX')
                m.logout()
                email_window.after(0, lambda: status_var.set('✅ اتصال ایمیل موفق بود.'))
                email_window.after(0, lambda: messagebox.showinfo('موفق', 'اتصال به ایمیل با موفقیت انجام شد.'))
            except Exception as e:
                email_window.after(0, lambda: status_var.set('❌ اتصال ناموفق'))
                email_window.after(0, lambda: messagebox.showerror('خطای اتصال', str(e)))
        threading.Thread(target=worker, daemon=True).start()

    btns = tk.Frame(email_window)
    btns.pack(fill=tk.X, padx=10, pady=5)
    tk.Button(btns, text='💾 ذخیره تنظیمات', command=save_settings).pack(side=tk.RIGHT, padx=4)
    tk.Button(btns, text='🔌 تست اتصال', command=test_connection).pack(side=tk.RIGHT, padx=4)

    body = tk.PanedWindow(email_window, orient=tk.HORIZONTAL, sashrelief=tk.RAISED)
    body.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

    left = tk.Frame(body)
    right = tk.Frame(body)
    body.add(left, width=430)
    body.add(right)

    tree = ttk.Treeview(left, columns=('from','subject','date'), show='headings', height=22)
    tree.heading('from', text='فرستنده')
    tree.heading('subject', text='موضوع')
    tree.heading('date', text='تاریخ')
    tree.column('from', width=135)
    tree.column('subject', width=180)
    tree.column('date', width=110)
    tree.pack(fill=tk.BOTH, expand=True)

    detail = scrolledtext.ScrolledText(right, wrap=tk.WORD, font=('Tahoma', 11))
    detail.pack(fill=tk.BOTH, expand=True)

    emails_cache = []

    def load_inbox():
        def worker():
            try:
                c = current_config()
                pwd = password_var.get() or _get_email_password(c['email'])
                if not pwd:
                    raise ValueError('رمز/رمز برنامه را وارد کنید.')
                m = _imap_connect(c, pwd)
                m.select('INBOX')
                typ, data = m.search(None, 'ALL')
                ids = data[0].split()[-30:]
                result = []
                for eid in reversed(ids):
                    typ, msg_data = m.fetch(eid, '(RFC822)')
                    raw = None
                    for item in msg_data:
                        if isinstance(item, tuple):
                            raw = item[1]
                            break
                    if not raw:
                        continue
                    msg = message_from_bytes(raw)
                    item = {
                        'id': eid,
                        'from': _decode_email_header(msg.get('From','')),
                        'subject': _decode_email_header(msg.get('Subject','(بدون موضوع)')),
                        'date': msg.get('Date',''),
                        'body': _extract_email_body(msg)
                    }
                    result.append(item)
                m.logout()
                def update():
                    emails_cache.clear(); emails_cache.extend(result)
                    for item in tree.get_children(): tree.delete(item)
                    for idx,item in enumerate(result):
                        tree.insert('', 'end', iid=str(idx), values=(item['from'], item['subject'], item['date']))
                    status_var.set(f'✅ {len(result)} ایمیل آخر بارگذاری شد.')
                email_window.after(0, update)
            except Exception as e:
                email_window.after(0, lambda: messagebox.showerror('خطای دریافت ایمیل', str(e)))
        threading.Thread(target=worker, daemon=True).start()

    def show_selected(_=None):
        sel = tree.selection()
        if not sel:
            return
        item = emails_cache[int(sel[0])]
        detail.delete('1.0', tk.END)
        detail.insert(tk.END, f"فرستنده: {item['from']}\nموضوع: {item['subject']}\nتاریخ: {item['date']}\n\n{item['body']}")

    tree.bind('<<TreeviewSelect>>', show_selected)

    compose = tk.LabelFrame(right, text='✉️ ارسال ایمیل')
    compose.pack(fill=tk.X, pady=6)
    to_var = tk.StringVar(); subj_var = tk.StringVar(); cc_var = tk.StringVar(); bcc_var = tk.StringVar()
    tk.Label(compose, text='گیرنده').grid(row=0,column=0,padx=5,pady=3)
    tk.Entry(compose, textvariable=to_var).grid(row=0,column=1,columnspan=3,sticky='ew',padx=5)
    tk.Label(compose, text='رونوشت').grid(row=1,column=0,padx=5,pady=3)
    tk.Entry(compose, textvariable=cc_var).grid(row=1,column=1,columnspan=3,sticky='ew',padx=5)
    tk.Label(compose, text='مخفی').grid(row=2,column=0,padx=5,pady=3)
    tk.Entry(compose, textvariable=bcc_var).grid(row=2,column=1,columnspan=3,sticky='ew',padx=5)
    tk.Label(compose, text='موضوع').grid(row=3,column=0,padx=5,pady=3)
    tk.Entry(compose, textvariable=subj_var).grid(row=3,column=1,columnspan=3,sticky='ew',padx=5)
    body_entry = scrolledtext.ScrolledText(compose, height=8, wrap=tk.WORD)
    body_entry.grid(row=4,column=0,columnspan=4,sticky='ew',padx=5,pady=5)
    for col in range(4): compose.columnconfigure(col, weight=1)

    def send_email():
        def worker():
            try:
                c = current_config()
                pwd = password_var.get() or _get_email_password(c['email'])
                if not pwd:
                    raise ValueError('رمز/رمز برنامه را وارد کنید.')
                _smtp_send(c, pwd, to_var.get(), subj_var.get(), body_entry.get('1.0',tk.END).strip(), cc_var.get(), bcc_var.get())
                email_window.after(0, lambda: messagebox.showinfo('موفق', 'ایمیل ارسال شد.'))
                email_window.after(0, lambda: status_var.set('✅ ایمیل ارسال شد.'))
            except Exception as e:
                email_window.after(0, lambda: messagebox.showerror('خطای ارسال', str(e)))
        threading.Thread(target=worker, daemon=True).start()

    tk.Button(compose, text='📨 ارسال', command=send_email).grid(row=5,column=3,padx=5,pady=5,sticky='e')
    tk.Button(left, text='🔄 دریافت ایمیل‌ها', command=load_inbox).pack(fill=tk.X, pady=5)

    ai_frame = tk.Frame(right)
    ai_frame.pack(fill=tk.X, pady=5)
    def summarize_selected():
        sel = tree.selection()
        if not sel:
            messagebox.showwarning('انتخاب ایمیل', 'ابتدا یک ایمیل را انتخاب کنید.')
            return
        item = emails_cache[int(sel[0])]
        prompt = f"این ایمیل را برای مدیر خلاصه کن و نکات مهم، کارهای لازم و موارد مشکوک را بگو:\nفرستنده: {item['from']}\nموضوع: {item['subject']}\nمتن:\n{item['body'][:12000]}"
        try:
            payload = {'model':get_ai_model(),'messages':[{'role':'user','content':prompt}],'stream':False}
            r = requests.post('http://localhost:11434/api/chat', json=payload, timeout=120)
            r.raise_for_status()
            answer = r.json()['message']['content']
            detail.delete('1.0', tk.END)
            detail.insert(tk.END, '🧠 خلاصه هوش مصنوعی:\n\n' + answer)
            save_email_insight(
                c.get('email',''),
                item.get('from',''),
                item.get('subject',''),
                answer,
                'high' if any(x in answer for x in ['فوری', 'مهم', 'خطر', 'زیاد']) else 'medium'
            )
            remember_ai_learning('ایمیل', answer, source='email_analysis', confidence=0.8)
        except Exception as e:
            messagebox.showerror('خطای هوش مصنوعی', str(e))

    tk.Button(ai_frame, text='🧠 خلاصه و تحلیل با هوش مصنوعی', command=summarize_selected).pack(side=tk.RIGHT)

# =========================================================
# صدا
# =========================================================

def speak_text(text):
    """پخش صدای فارسی در پس‌زمینه؛ برای هر درخواست فایل جدا ساخته می‌شود."""
    text = str(text or "").strip()
    if not text:
        return
    def _worker():
        voice_file = os.path.join(BASE_DIR, f"ai_voice_{threading.get_ident()}.mp3")
        try:
            if edge_tts is None:
                print("Voice error: edge-tts نصب نیست.")
                return
            asyncio.run(edge_tts.Communicate(text[:6000], "fa-IR-DilaraNeural").save(voice_file))
            if playsound is not None:
                playsound(voice_file)
            elif os.name == "nt":
                os.startfile(voice_file)
            else:
                print("Voice error: پخش‌کننده صوتی در دسترس نیست.")
        except Exception as e:
            print("Voice error:", e)
            try:
                if os.name == "nt" and os.path.exists(voice_file):
                    os.startfile(voice_file)
            except Exception as fallback_error:
                print("Voice fallback error:", fallback_error)
    threading.Thread(target=_worker, daemon=True).start()


# =========================================================
# حافظه هوش مصنوعی
# =========================================================

def ensure_core_memory():
    """حافظه اصلی هویتی؛ با پاک‌سازی اطلاعات آزمایشی حذف نمی‌شود."""
    default = {"creator_name": CREATOR_NAME, "creator_national_id": CREATOR_NATIONAL_ID, "identity": "خالق و مالک اصلی سیستم", "language": "فارسی", "purpose": "مدیریت فروشگاه، انبار، خرید، فروش و حسابداری", "protected": True, "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
    try:
        if not os.path.exists(CORE_MEMORY_FILE):
            with open(CORE_MEMORY_FILE, "w", encoding="utf-8") as f: json.dump(default, f, ensure_ascii=False, indent=2)
        else:
            with open(CORE_MEMORY_FILE, "r", encoding="utf-8") as f: data=json.load(f)
            changed=False
            for k,v in default.items():
                if k not in data: data[k]=v; changed=True
            if changed:
                with open(CORE_MEMORY_FILE, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception as e: print("Core memory error:", e)

def get_core_memory():
    ensure_core_memory()
    try:
        with open(CORE_MEMORY_FILE, "r", encoding="utf-8") as f: return json.load(f)
    except Exception:
        return {"creator_name": CREATOR_NAME, "creator_national_id": CREATOR_NATIONAL_ID, "identity": "خالق و مالک اصلی سیستم", "protected": True}

ensure_core_memory()

def load_memory():
    global conversation

    if os.path.exists(MEMORY_FILE):
        try:
            with open(
                MEMORY_FILE,
                "r",
                encoding="utf-8"
            ) as file:
                conversation = json.load(file)

        except Exception:
            conversation = []


def save_memory():
    try:
        with open(
            MEMORY_FILE,
            "w",
            encoding="utf-8"
        ) as file:

            json.dump(
                conversation,
                file,
                ensure_ascii=False,
                indent=2
            )

    except Exception as e:
        print("Memory error:", e)


# =========================================================
# تقسیم فایل
# =========================================================

def create_chunks(text):

    text = re.sub(
        r"\s+",
        " ",
        text
    ).strip()

    chunks = []

    chunk_size = 1400
    overlap = 200

    start = 0

    while start < len(text):

        end = start + chunk_size

        chunk = text[start:end]

        if chunk.strip():
            chunks.append(chunk)

        start += chunk_size - overlap

    return chunks


# =========================================================
# PDF
# =========================================================

def read_pdf(file_path):

    reader = PdfReader(file_path)

    text = ""

    for page in reader.pages:

        page_text = page.extract_text()

        if page_text:
            text += page_text + "\n"

    return text


# =========================================================
# Word
# =========================================================

def read_word(file_path):

    document = Document(file_path)

    text = ""

    for paragraph in document.paragraphs:
        text += paragraph.text + "\n"

    return text


# =========================================================
# تست صدا
# =========================================================
def test_voice():
    speak_text("سلام امید اسکندری. صدای برنامه در حال آزمایش است.")
    try:
        messagebox.showinfo("تست صدا", "صدای آزمایشی در حال پخش است. اگر صدا پخش نشد، پیام Voice error را در CMD بررسی کنید.")
    except Exception:
        pass

# =========================================================
# فایل‌ها
# =========================================================

def update_file_list():

    file_list.delete(
        0,
        tk.END
    )

    for file_data in files_data:

        file_list.insert(
            tk.END,
            "📄 " + file_data["name"]
        )

    file_count_label.config(
        text="تعداد فایل‌ها: "
        + str(len(files_data))
    )


def open_files():

    global files_data

    file_paths = filedialog.askopenfilenames(
        title="انتخاب چند فایل",
        filetypes=[
            (
                "PDF و Word",
                "*.pdf *.docx"
            ),
            (
                "PDF",
                "*.pdf"
            ),
            (
                "Word",
                "*.docx"
            )
        ]
    )

    if not file_paths:
        return

    added_count = 0

    for file_path in file_paths:

        already_exists = False

        for file_data in files_data:

            if file_data["path"] == file_path:
                already_exists = True
                break

        if already_exists:
            continue

        try:

            file_name = os.path.basename(
                file_path
            )

            if file_path.lower().endswith(".pdf"):

                text = read_pdf(file_path)

            elif file_path.lower().endswith(".docx"):

                text = read_word(file_path)

            else:
                continue

            chunks = create_chunks(text)

            files_data.append({
                "name": file_name,
                "path": file_path,
                "chunks": chunks
            })

            added_count += 1

            chat.insert(
                tk.END,
                "\n📚 فایل اضافه شد:\n"
                + file_name
                + "\nتعداد بخش‌ها: "
                + str(len(chunks))
                + "\n\n"
            )

        except Exception as e:

            chat.insert(
                tk.END,
                "خطا در خواندن فایل:\n"
                + str(e)
                + "\n\n"
            )

    update_file_list()

    if added_count > 0:
        chat.see(tk.END)


def remove_selected_file():

    selection = file_list.curselection()

    if not selection:

        chat.insert(
            tk.END,
            "\n⚠️ ابتدا یک فایل را انتخاب کن.\n\n"
        )

        return

    index = selection[0]

    file_name = files_data[index]["name"]

    del files_data[index]

    update_file_list()

    chat.insert(
        tk.END,
        "\n🗑️ فایل حذف شد:\n"
        + file_name
        + "\n\n"
    )

    chat.see(tk.END)


def clear_files():

    global files_data

    files_data = []

    update_file_list()

    chat.insert(
        tk.END,
        "\n🗑️ همه فایل‌ها پاک شدند.\n\n"
    )

    chat.see(tk.END)


# =========================================================
# جست‌وجو در فایل‌ها
# =========================================================

def search_files(question):

    if not files_data:
        return ""

    words = re.findall(
        r"[\wآ-ی]+",
        question.lower()
    )

    results = []

    for file_data in files_data:

        file_name = file_data["name"]

        for chunk in file_data["chunks"]:

            score = 0

            chunk_lower = chunk.lower()

            for word in words:

                if len(word) >= 2 and word in chunk_lower:
                    score += 1

            if score > 0:

                results.append(
                    (
                        score,
                        file_name,
                        chunk
                    )
                )

    results.sort(
        reverse=True,
        key=lambda x: x[0]
    )

    top_results = results[:2]

    context = ""

    for score, file_name, chunk in top_results:

        context += (
            "\n\n--- فایل: "
            + file_name
            + " ---\n"
            + chunk
        )

    return context


# =========================================================
# اطلاعات انبار
# =========================================================

def get_inventory_text():

    cursor.execute("""
        SELECT code, name, quantity,
               buy_price, sell_price, unit
        FROM products
        ORDER BY name
    """)

    rows = cursor.fetchall()

    if not rows:
        return "انبار خالی است."

    text = ""

    for row in rows:

        code, name, quantity, buy_price, sell_price, unit = row

        text += (
            "\n"
            "کد: " + str(code)
            + " | کالا: " + str(name)
            + " | موجودی: " + str(quantity)
            + " " + str(unit)
            + " | قیمت خرید: " + str(buy_price)
            + " | قیمت فروش: " + str(sell_price)
        )

    return text


# =========================================================
# جست‌وجوی انبار
# =========================================================

def search_inventory(question):

    try:

        cursor.execute("""
            SELECT code, name, quantity, buy_price, sell_price, unit
            FROM products
        """)

        rows = cursor.fetchall()

        if not rows:
            return "انبار خالی است."

        question_lower = question.lower()

        results = []

        for row in rows:

            code, name, quantity, buy_price, sell_price, unit = row

            name_lower = str(name).lower()

            if name_lower in question_lower:

                results.append(row)

        if not results:

            words = re.findall(
                r"[\wآ-ی]+",
                question_lower
            )

            for row in rows:

                code, name, quantity, buy_price, sell_price, unit = row

                searchable = (
                    str(code)
                    + " "
                    + str(name)
                ).lower()

                for word in words:

                    if len(word) >= 2 and word in searchable:

                        results.append(row)
                        break

        if not results:

            return "کالای موردنظر در انبار پیدا نشد."

        text = ""

        for row in results[:10]:

            code, name, quantity, buy_price, sell_price, unit = row

            text += (
                "نام کالا: " + str(name)
                + "\nموجودی واقعی: "
                + str(quantity)
                + " "
                + str(unit)
                + "\nقیمت خرید: "
                + str(buy_price)
                + "\nقیمت فروش: "
                + str(sell_price)
                + "\n\n"
            )

        return text

    except Exception as e:

        return "خطا در خواندن موجودی: " + str(e)


# =========================================================
# پنجره انبار
# =========================================================

def open_inventory_window():

    inventory_window = tk.Toplevel(window)

    inventory_window.title("📦 انبار")

    inventory_window.geometry("950x650")

    form = tk.Frame(inventory_window)
    form.pack(
        fill=tk.X,
        padx=10,
        pady=10
    )

    tk.Label(
        form,
        text="کد کالا"
    ).grid(
        row=0,
        column=0,
        padx=5,
        pady=5
    )

    code_entry = tk.Entry(
        form,
        width=18
    )

    code_entry.grid(
        row=0,
        column=1,
        padx=5
    )

    tk.Label(
        form,
        text="نام کالا"
    ).grid(
        row=0,
        column=2,
        padx=5
    )

    name_entry = tk.Entry(
        form,
        width=20
    )

    name_entry.grid(
        row=0,
        column=3,
        padx=5
    )

    tk.Label(
        form,
        text="موجودی"
    ).grid(
        row=1,
        column=0,
        padx=5,
        pady=5
    )

    quantity_entry = tk.Entry(
        form,
        width=18
    )

    quantity_entry.grid(
        row=1,
        column=1,
        padx=5
    )

    tk.Label(
        form,
        text="قیمت خرید"
    ).grid(
        row=1,
        column=2,
        padx=5
    )

    buy_entry = tk.Entry(
        form,
        width=20
    )

    buy_entry.grid(
        row=1,
        column=3,
        padx=5
    )

    tk.Label(
        form,
        text="قیمت فروش"
    ).grid(
        row=2,
        column=0,
        padx=5,
        pady=5
    )

    sell_entry = tk.Entry(
        form,
        width=18
    )

    sell_entry.grid(
        row=2,
        column=1,
        padx=5
    )

    tk.Label(
        form,
        text="واحد"
    ).grid(
        row=2,
        column=2,
        padx=5
    )

    unit_entry = tk.Entry(
        form,
        width=20
    )

    unit_entry.insert(
        0,
        "عدد"
    )

    unit_entry.grid(
        row=2,
        column=3,
        padx=5
    )

    # =====================================================
    # جدول
    # =====================================================

    table_frame = tk.Frame(inventory_window)

    table_frame.pack(
        fill=tk.BOTH,
        expand=True,
        padx=10,
        pady=10
    )

    columns = (
        "id",
        "code",
        "name",
        "quantity",
        "buy",
        "sell",
        "unit"
    )

    table = ttk.Treeview(
        table_frame,
        columns=columns,
        show="headings"
    )

    headings = {
        "id": "شناسه",
        "code": "کد",
        "name": "نام کالا",
        "quantity": "موجودی",
        "buy": "خرید",
        "sell": "فروش",
        "unit": "واحد"
    }

    for col, text in headings.items():
        table.heading(
            col,
            text=text
        )

    table.column("id", width=60)
    table.column("code", width=100)
    table.column("name", width=200)
    table.column("quantity", width=100)
    table.column("buy", width=100)
    table.column("sell", width=100)
    table.column("unit", width=80)

    table.pack(
        fill=tk.BOTH,
        expand=True
    )

    # =====================================================
    # بروزرسانی جدول
    # =====================================================

    def refresh_table():

        for item in table.get_children():
            table.delete(item)

        cursor.execute("""
            SELECT id, code, name,
                   quantity, buy_price,
                   sell_price, unit
            FROM products
            ORDER BY id DESC
        """)

        for row in cursor.fetchall():

            table.insert(
                "",
                tk.END,
                values=row
            )

    # =====================================================
    # پاک کردن فرم
    # =====================================================

    def clear_form():

        code_entry.delete(0, tk.END)
        name_entry.delete(0, tk.END)
        quantity_entry.delete(0, tk.END)
        buy_entry.delete(0, tk.END)
        sell_entry.delete(0, tk.END)

        unit_entry.delete(0, tk.END)
        unit_entry.insert(0, "عدد")

    # =====================================================
    # ثبت کالا
    # =====================================================

    def add_product():

        code = code_entry.get().strip()
        name = name_entry.get().strip()
        quantity = quantity_entry.get().strip()
        buy_price = buy_entry.get().strip()
        sell_price = sell_entry.get().strip()
        unit = unit_entry.get().strip()

        if not code or not name:

            messagebox.showwarning(
                "توجه",
                "کد کالا و نام کالا را وارد کنید."
            )

            return

        try:

            quantity = float(quantity or 0)
            buy_price = float(buy_price or 0)
            sell_price = float(sell_price or 0)

        except ValueError:

            messagebox.showerror(
                "خطا",
                "تعداد و قیمت‌ها باید عدد باشند."
            )

            return

        try:

            cursor.execute("""
                INSERT INTO products
                (
                    code,
                    name,
                    quantity,
                    buy_price,
                    sell_price,
                    unit
                )
                VALUES (?, ?, ?, ?, ?, ?)
            """, (
                code,
                name,
                quantity,
                buy_price,
                sell_price,
                unit or "عدد"
            ))

            conn.commit()
            log_employee_activity("کارمند انبار", "ثبت کالا", str(name))

            refresh_table()
            clear_form()

            messagebox.showinfo(
                "موفق",
                "کالا با موفقیت ثبت شد."
            )

        except sqlite3.IntegrityError:

            messagebox.showerror(
                "خطا",
                "این کد کالا قبلاً ثبت شده است."
            )

    # =====================================================
    # افزایش موجودی
    # =====================================================

    def increase_stock():

        selection = table.selection()

        if not selection:

            messagebox.showwarning(
                "توجه",
                "ابتدا یک کالا را انتخاب کنید."
            )

            return

        values = table.item(
            selection[0]
        )["values"]

        product_id = values[0]

        amount = quantity_entry.get().strip()

        try:
            amount = float(amount)

        except ValueError:

            messagebox.showerror(
                "خطا",
                "مقدار باید عدد باشد."
            )

            return

        if amount <= 0:

            messagebox.showwarning(
                "توجه",
                "مقدار باید بیشتر از صفر باشد."
            )

            return

        cursor.execute("""
            UPDATE products
            SET quantity = quantity + ?
            WHERE id = ?
        """, (
            amount,
            product_id
        ))

        conn.commit()

        refresh_table()
        clear_form()

        messagebox.showinfo(
            "موفق",
            "موجودی افزایش یافت."
        )

    # =====================================================
    # کاهش موجودی
    # =====================================================

    def decrease_stock():

        selection = table.selection()

        if not selection:

            messagebox.showwarning(
                "توجه",
                "ابتدا یک کالا را انتخاب کنید."
            )

            return

        values = table.item(
            selection[0]
        )["values"]

        product_id = values[0]

        amount = quantity_entry.get().strip()

        try:
            amount = float(amount)

        except ValueError:

            messagebox.showerror(
                "خطا",
                "مقدار باید عدد باشد."
            )

            return

        if amount <= 0:

            messagebox.showwarning(
                "توجه",
                "مقدار باید بیشتر از صفر باشد."
            )

            return

        cursor.execute("""
            SELECT quantity
            FROM products
            WHERE id = ?
        """, (
            product_id,
        ))

        row = cursor.fetchone()

        if not row:
            return

        current_quantity = float(row[0])

        if amount > current_quantity:

            messagebox.showwarning(
                "موجودی کافی نیست",
                "موجودی فعلی کافی نیست."
            )

            return

        cursor.execute("""
            UPDATE products
            SET quantity = quantity - ?
            WHERE id = ?
        """, (
            amount,
            product_id
        ))

        conn.commit()

        refresh_table()
        clear_form()

        messagebox.showinfo(
            "موفق",
            "موجودی کاهش یافت."
        )

    # =====================================================
    # حذف کالا
    # =====================================================

    def delete_product():

        selection = table.selection()

        if not selection:

            messagebox.showwarning(
                "توجه",
                "ابتدا یک کالا را انتخاب کنید."
            )

            return

        values = table.item(
            selection[0]
        )["values"]

        product_id = values[0]

        answer = messagebox.askyesno(
            "حذف کالا",
            "آیا از حذف این کالا مطمئن هستید؟"
        )

        if not answer:
            return

        cursor.execute("""
            DELETE FROM products
            WHERE id = ?
        """, (
            product_id,
        ))

        conn.commit()

        refresh_table()
        clear_form()

    # =====================================================
    # انتخاب کالا
    # =====================================================

    def select_product(event=None):

        selection = table.selection()

        if not selection:
            return

        values = table.item(
            selection[0]
        )["values"]

        clear_form()

        code_entry.insert(0, values[1])
        name_entry.insert(0, values[2])
        quantity_entry.insert(0, values[3])
        buy_entry.insert(0, values[4])
        sell_entry.insert(0, values[5])
        unit_entry.insert(0, values[6])

    table.bind(
        "<<TreeviewSelect>>",
        select_product
    )

    # =====================================================
    # دکمه‌ها
    # =====================================================

    buttons = tk.Frame(inventory_window)

    buttons.pack(
        fill=tk.X,
        padx=10,
        pady=5
    )

    tk.Button(
        buttons,
        text="➕ ثبت کالای جدید",
        command=add_product,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="⬆️ ورود کالا",
        command=increase_stock,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="⬇️ خروج کالا",
        command=decrease_stock,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="🗑️ حذف کالا",
        command=delete_product,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="🔄 بروزرسانی",
        command=refresh_table,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="پاک کردن فرم",
        command=clear_form,
        font=("Tahoma", 10)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    refresh_table()

 
# =========================================================
# 🛒 فروشگاه
# =========================================================

# =========================================================
# تعریف جنس توسط موسی
# =========================================================
PRODUCT_CATEGORIES = ["خوراکی", "مواد شوینده", "گوشت"]
CATEGORY_PREFIX = {"خوراکی": "KH", "مواد شوینده": "SH", "گوشت": "GT"}
try:
    cursor.execute("PRAGMA table_info(products)")
    _pc=[r[1] for r in cursor.fetchall()]
    if "category" not in _pc:
        cursor.execute("ALTER TABLE products ADD COLUMN category TEXT DEFAULT 'خوراکی'")
    cursor.execute("UPDATE products SET category='خوراکی' WHERE category IS NULL OR TRIM(category)=''")
    conn.commit()
except Exception:
    pass

def generate_product_code(category):
    prefix=CATEGORY_PREFIX.get(category,"KH")
    cursor.execute("SELECT code FROM products WHERE code LIKE ?",(prefix+"-%",))
    nums=[]
    for (c,) in cursor.fetchall():
        try: nums.append(int(str(c).split("-")[-1]))
        except: pass
    return f"{prefix}-{(max(nums)+1 if nums else 1):04d}"

def open_product_definition_window(parent=None):
    active=get_active_employee()
    if active not in ("موسی","مالک"):
        messagebox.showwarning("دسترسی","فقط موسی یا مالک می‌تواند جنس جدید تعریف کند.",parent=parent or window); return
    win=tk.Toplevel(parent or window); win.title("➕ تعریف جنس"); win.geometry("600x430")
    tk.Label(win,text="➕ تعریف جنس جدید",font=("Tahoma",17,"bold")).pack(pady=12)
    form=tk.Frame(win); form.pack(padx=25,pady=5)
    tk.Label(form,text="دسته‌بندی:",font=("Tahoma",11)).grid(row=0,column=0,padx=5,pady=7,sticky="e")
    cat=tk.StringVar(value=PRODUCT_CATEGORIES[0])
    combo=ttk.Combobox(form,textvariable=cat,values=PRODUCT_CATEGORIES,state="readonly",width=27,font=("Tahoma",11)); combo.grid(row=0,column=1,padx=5,pady=7)
    labels=["نام جنس:","واحد:","قیمت خرید:","قیمت فروش:"]
    es={}
    for r,l in enumerate(labels,1):
        tk.Label(form,text=l,font=("Tahoma",11)).grid(row=r,column=0,padx=5,pady=7,sticky="e")
        e=tk.Entry(form,width=29,font=("Tahoma",11)); e.grid(row=r,column=1,padx=5,pady=7); es[l]=e
    es["واحد:"].insert(0,"عدد")
    code=tk.StringVar(value=generate_product_code(cat.get()))
    tk.Label(form,text="کد خودکار:",font=("Tahoma",11)).grid(row=5,column=0,padx=5,pady=7,sticky="e")
    tk.Label(form,textvariable=code,font=("Tahoma",11,"bold")).grid(row=5,column=1,padx=5,pady=7,sticky="w")
    combo.bind("<<ComboboxSelected>>",lambda e: code.set(generate_product_code(cat.get())))
    def save():
        try:
            category=cat.get(); name=es["نام جنس:"].get().strip(); unit=es["واحد:"].get().strip() or "عدد"
            buy=float(es["قیمت خرید:"].get().strip() or 0); sell=float(es["قیمت فروش:"].get().strip() or 0)
            if not name: raise ValueError("نام جنس را وارد کنید.")
            if buy<0 or sell<0: raise ValueError("قیمت نمی‌تواند منفی باشد.")
            c=generate_product_code(category)
            cursor.execute("INSERT INTO products(code,name,quantity,buy_price,sell_price,unit,category) VALUES(?,?,?,?,?,?,?)",(c,name,0,buy,sell,unit,category))
            conn.commit(); log_employee_activity(active,"تعریف جنس",f"{name} | {category} | {c}")
            messagebox.showinfo("ثبت شد",f"جنس «{name}» ثبت شد.\nکد: {c}",parent=win); win.destroy()
        except Exception as e: messagebox.showerror("خطا",str(e),parent=win)
    tk.Button(win,text="💾 ذخیره جنس",font=("Tahoma",11,"bold"),command=save).pack(pady=12)
    tk.Button(win,text="بستن",command=win.destroy).pack()

def open_store_window():

    store_window = tk.Toplevel(window)

    store_window.title("🛒 فروشگاه")

    store_window.geometry("1000x700")

    tk.Label(
        store_window,
        text="🛒 فروشگاه",
        font=("Tahoma", 18, "bold")
    ).pack(
        pady=10
    )

    # =====================================================
    # جست‌وجو
    # =====================================================

    search_frame = tk.Frame(store_window)

    search_frame.pack(
        fill=tk.X,
        padx=15,
        pady=5
    )

    tk.Label(
        search_frame,
        text="جست‌وجوی کالا:",
        font=("Tahoma", 11)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    search_entry = tk.Entry(
        search_frame,
        font=("Tahoma", 12)
    )

    search_entry.pack(
        side=tk.LEFT,
        fill=tk.X,
        expand=True,
        padx=5
    )

    # =====================================================
    # جدول کالاها
    # =====================================================

    products_frame = tk.Frame(store_window)

    products_frame.pack(
        fill=tk.BOTH,
        expand=True,
        padx=15,
        pady=10
    )

    product_columns = (
        "id",
        "code",
        "name",
        "quantity",
        "price",
        "unit"
    )

    product_table = ttk.Treeview(
        products_frame,
        columns=product_columns,
        show="headings"
    )

    product_headings = {
        "id": "شناسه",
        "code": "کد",
        "name": "نام کالا",
        "quantity": "موجودی",
        "price": "قیمت فروش",
        "unit": "واحد"
    }

    for col, text in product_headings.items():

        product_table.heading(
            col,
            text=text
        )

    product_table.column("id", width=60)
    product_table.column("code", width=100)
    product_table.column("name", width=220)
    product_table.column("quantity", width=100)
    product_table.column("price", width=130)
    product_table.column("unit", width=80)

    product_table.pack(
        fill=tk.BOTH,
        expand=True
    )

       # =====================================================
    # فرم فروش
    # =====================================================

    sale_frame = tk.Frame(
        store_window,
        relief=tk.GROOVE,
        borderwidth=2
    )

    sale_frame.pack(
        fill=tk.X,
        padx=15,
        pady=10
    )

    tk.Label(
        sale_frame,
        text="کالای انتخاب‌شده:",
        font=("Tahoma", 10)
    ).grid(
        row=0,
        column=0,
        padx=5,
        pady=8
    )

    selected_name_label = tk.Label(
        sale_frame,
        text="---",
        font=("Tahoma", 11, "bold")
    )

    selected_name_label.grid(
        row=0,
        column=1,
        padx=10
    )

    tk.Label(
        sale_frame,
        text="تعداد فروش:",
        font=("Tahoma", 10)
    ).grid(
        row=0,
        column=2,
        padx=5
    )

    sale_quantity_entry = tk.Entry(
        sale_frame,
        width=12,
        font=("Tahoma", 11)
    )

    sale_quantity_entry.insert(
        0,
        "1"
    )

    sale_quantity_entry.grid(
        row=0,
        column=3,
        padx=5
    )

    tk.Label(
        sale_frame,
        text="قیمت واحد:",
        font=("Tahoma", 10)
    ).grid(
        row=1,
        column=0,
        padx=5,
        pady=8
    )

    unit_price_label = tk.Label(
        sale_frame,
        text="0",
        font=("Tahoma", 11, "bold")
    )

    unit_price_label.grid(
        row=1,
        column=1,
        padx=10
    )

    tk.Label(
        sale_frame,
        text="مبلغ کل:",
        font=("Tahoma", 10)
    ).grid(
        row=1,
        column=2,
        padx=5
    )

    total_label = tk.Label(
        sale_frame,
        text="0",
        font=("Tahoma", 12, "bold")
    )

    total_label.grid(
        row=1,
        column=3,
        padx=5
    )

    selected_product = {
        "id": None,
        "code": "",
        "name": "",
        "quantity": 0,
        "price": 0,
        "unit": "",
        "category": "خوراکی"
    }

    # =====================================================
    # انتخاب مشتری
    # =====================================================

    tk.Label(
        sale_frame,
        text="مشتری:",
        font=("Tahoma", 10)
    ).grid(
        row=2,
        column=0,
        padx=5,
        pady=8
    )

    customer_var = tk.StringVar()

    customer_combo = ttk.Combobox(
        sale_frame,
        textvariable=customer_var,
        width=35,
        font=("Tahoma", 10),
        state="readonly"
    )

    customer_combo.grid(
        row=2,
        column=1,
        columnspan=2,
        padx=10,
        pady=8
    )

    tk.Label(sale_frame, text="روش تسویه:", font=("Tahoma", 10, "bold")).grid(row=3,column=0,padx=5,pady=8)
    payment_var=tk.StringVar(value="صندوق")
    payment_combo=ttk.Combobox(sale_frame,textvariable=payment_var,values=["صندوق","بانک","نسیه مشتری"],state="readonly",width=20,font=("Tahoma",10))
    payment_combo.grid(row=3,column=1,padx=10,pady=8,sticky="w")
    tk.Label(sale_frame,text="نسیه فقط با انتخاب مشتری ثبت می‌شود.",font=("Tahoma",9)).grid(row=3,column=2,columnspan=2,sticky="w")

    customer_data = {}

    def load_customers():

        customer_data.clear()

        cursor.execute("""
            SELECT id, name, phone
            FROM customers
            ORDER BY name
        """)

        rows = cursor.fetchall()

        customer_names = [
            "بدون مشتری"
        ]

        customer_data["بدون مشتری"] = None

        for customer_id, name, phone in rows:

            display_name = str(name)

            if phone:
                display_name += " - " + str(phone)

            customer_names.append(
                display_name
            )

            customer_data[
                display_name
            ] = customer_id

        customer_combo["values"] = customer_names

        customer_combo.current(0)

    load_customers()

    # =====================================================
    # بروزرسانی فروشگاه
    # =====================================================

    def refresh_store():

        for item in product_table.get_children():
            product_table.delete(item)

        search_text = (
            search_entry.get()
            .strip()
            .lower()
        )

        cursor.execute("""
            SELECT id, code, name,
                   quantity, sell_price, unit
            FROM products
            ORDER BY name
        """)

        rows = cursor.fetchall()

        for row in rows:

            row_text = (
                str(row[1])
                + " "
                + str(row[2])
            ).lower()

            if (
                search_text
                and search_text not in row_text
            ):
                continue

            product_table.insert(
                "",
                tk.END,
                values=row
            )

    # =====================================================
    # انتخاب کالا
    # =====================================================

    def select_store_product(event=None):

        selection = product_table.selection()

        if not selection:
            return

        values = product_table.item(
            selection[0]
        )["values"]

        selected_product["id"] = values[0]
        selected_product["code"] = values[1]
        selected_product["name"] = values[2]
        selected_product["quantity"] = float(values[3])
        selected_product["price"] = float(values[4])
        selected_product["unit"] = values[5]

        selected_name_label.config(
            text=str(values[2])
        )

        unit_price_label.config(
            text=f"{float(values[4]):,.0f}"
        )

        update_total()

    product_table.bind(
        "<<TreeviewSelect>>",
        select_store_product
    )

    # =====================================================
    # محاسبه مبلغ
    # =====================================================

    def update_total(event=None):

        try:

            quantity = float(
                sale_quantity_entry.get()
            )

            price = float(
                selected_product["price"]
            )

            total = quantity * price

            total_label.config(
                text=f"{total:,.0f}"
            )

        except Exception:

            total_label.config(
                text="0"
            )

    sale_quantity_entry.bind(
        "<KeyRelease>",
        update_total
    )

    # =====================================================
    # فاکتور
    # =====================================================

    def show_invoice(
        sale_id,
        sale_date,
        code,
        name,
        quantity,
        price,
        total,
        unit,
        customer_name="بدون مشتری",
        customer_phone="",
        payment_mode="صندوق"
    ):

        invoice_window = tk.Toplevel(
            store_window
        )

        invoice_window.title(
            "🧾 فاکتور فروش"
        )

        invoice_window.geometry(
            "600x600"
        )

        tk.Label(
            invoice_window,
            text="🧾 فاکتور فروش",
            font=("Tahoma", 20, "bold")
        ).pack(
            pady=15
        )

        invoice_text = scrolledtext.ScrolledText(
            invoice_window,
            wrap=tk.WORD,
            font=("Tahoma", 13),
            padx=20,
            pady=20
        )

        invoice_text.pack(
            fill=tk.BOTH,
            expand=True,
            padx=15,
            pady=10
        )

        invoice_text.insert(
            tk.END,
            "================================\n"
            "             فاکتور فروش\n"
            "================================\n\n"
            "شماره فاکتور: " + str(sale_id) + "\n"
            "تاریخ: " + str(sale_date) + "\n\n"
            "مشتری: " + str(customer_name) + "\n"
            "تلفن مشتری: " + str(customer_phone) + "\n"
            "روش تسویه: " + str(payment_mode) + "\n"
            "--------------------------------\n"
            "کد کالا: " + str(code) + "\n"
            "نام کالا: " + str(name) + "\n"
            "تعداد: " + str(quantity) + " " + str(unit) + "\n"
            "قیمت واحد: " + f"{price:,.0f}" + "\n"
            "--------------------------------\n"
            "مبلغ کل: " + f"{total:,.0f}" + "\n"
            "================================\n\n"
            "از خرید شما سپاسگزاریم 🌹"
        )

        invoice_text.config(
            state=tk.DISABLED
        )

        tk.Button(
            invoice_window,
            text="بستن",
            font=("Tahoma", 11),
            command=invoice_window.destroy
        ).pack(
            pady=10
        )

    # =====================================================
    # ثبت فروش
    # =====================================================

    def register_sale():

        product_id = selected_product["id"]

        customer_id = customer_data.get(
            customer_var.get()
        )

        if not product_id:

            messagebox.showwarning(
                "توجه",
                "ابتدا یک کالا را انتخاب کنید."
            )

            return

        try:

            quantity = float(
                sale_quantity_entry.get()
            )

        except ValueError:

            messagebox.showerror(
                "خطا",
                "تعداد فروش باید عدد باشد."
            )

            return

        if quantity <= 0:

            messagebox.showwarning(
                "توجه",
                "تعداد باید بیشتر از صفر باشد."
            )

            return

        cursor.execute("""
            SELECT code, name, quantity,
                   sell_price, unit
            FROM products
            WHERE id = ?
        """, (
            product_id,
        ))

        row = cursor.fetchone()

        if not row:

            messagebox.showerror(
                "خطا",
                "کالا پیدا نشد."
            )

            return

        code, name, current_quantity, price, unit = row

        current_quantity = float(
            current_quantity
        )

        price = float(
            price
        )

        if quantity > current_quantity:

            messagebox.showwarning(
                "موجودی کافی نیست",
                "موجودی این کالا کافی نیست.\n"
                + "موجودی فعلی: "
                + str(current_quantity)
                + " "
                + str(unit)
            )

            return

        total = quantity * price
        payment_mode=payment_var.get().strip() or "صندوق"
        if payment_mode == "نسیه مشتری" and not customer_id:
            messagebox.showwarning("مشتری لازم است","برای فروش نسیه ابتدا مشتری را انتخاب کنید.")
            return

        answer = messagebox.askyesno(
            "تأیید فروش",
            "کالا: " + str(name)
            + "\nتعداد: " + str(quantity)
            + " " + str(unit)
            + "\nقیمت واحد: "
            + f"{price:,.0f}"
            + "\nمبلغ کل: "
            + f"{total:,.0f}"
            + "\n\nآیا فروش ثبت شود؟"
        )

        if not answer:
            return

        # -------------------------------------------------
        # کم کردن موجودی
        # -------------------------------------------------

        cursor.execute("""
            UPDATE products
            SET quantity = quantity - ?
            WHERE id = ?
        """, (
            quantity,
            product_id
        ))

        # -------------------------------------------------
        # ثبت فروش
        # -------------------------------------------------

        sale_date = datetime.now().strftime(
            "%Y-%m-%d %H:%M:%S"
        )

        cursor.execute("""
            INSERT INTO sales
            (
                product_id,
                customer_id,
                code,
                name,
                quantity,
                price,
                total,
                sale_date,
                employee
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            product_id,
            customer_id,
            code,
            name,
            quantity,
            price,
            total,
            sale_date,
            get_active_employee()
        ))

        sale_id = cursor.lastrowid

        # ثبت هم‌زمان فروش، درآمد، دفتر کل و بهای تمام‌شده؛ در صورت خطا همه چیز rollback می‌شود.
        try:
            cogs = round(get_product_buy_price(product_id) * quantity, 2)
            sale_debit_account = "مشتریان" if payment_mode == "نسیه مشتری" else payment_mode
            post_simple(sale_debit_account, "فروش کالا", total,
                        description=f"فروش {name} - تعداد {quantity} | تسویه: {payment_mode}",
                        ref_type="sale", ref_id=sale_id, entry_date=sale_date, employee=get_active_employee(), commit=False)
            if cogs > 0:
                post_simple("بهای تمام‌شده کالای فروش‌رفته", "موجودی کالا", cogs,
                            description=f"بهای تمام‌شده {name} - تعداد {quantity}",
                            ref_type="sale_cogs", ref_id=sale_id, entry_date=sale_date, employee=get_active_employee(), commit=False)
            cursor.execute("""INSERT INTO accounting
                (entry_type,category,amount,description,related_sale_id,entry_date)
                VALUES (?,?,?,?,?,?)""",
                ("income","فروش کالا",total,"فروش "+str(name)+" - تعداد "+str(quantity),sale_id,sale_date))
            conn.commit()
        except Exception as ledger_err:
            conn.rollback()
            messagebox.showerror("خطا در ثبت فروش", f"فروش ثبت نشد و هیچ بخش مالی/موجودی اعمال نشد:\n{ledger_err}")
            return

        log_employee_activity("کارمند فروشگاه", "ثبت فروش", f"{name} | تعداد {quantity} | مبلغ {total:,.0f}")

        # -------------------------------------------------
        # اطلاعات مشتری برای فاکتور
        # -------------------------------------------------

        selected_customer_name = customer_var.get()

        selected_customer_phone = ""

        if customer_id:

            cursor.execute("""
                SELECT phone
                FROM customers
                WHERE id = ?
            """, (
                customer_id,
            ))

            customer_row = cursor.fetchone()

            if customer_row:
                selected_customer_phone = (
                    customer_row[0] or ""
                )

        # -------------------------------------------------
        # پیام فروش موفق
        # -------------------------------------------------

        messagebox.showinfo(
            "فروش موفق",
            "فروش با موفقیت ثبت شد.\n\n"
            + "کالا: " + str(name)
            + "\nتعداد: " + str(quantity)
            + "\nمبلغ: " + f"{total:,.0f}"
        )

        # -------------------------------------------------
        # نمایش فاکتور
        # -------------------------------------------------

        show_invoice(
            sale_id,
            sale_date,
            code,
            name,
            quantity,
            price,
            total,
            unit,
            selected_customer_name,
            selected_customer_phone,
            payment_mode
        )

        # -------------------------------------------------
        # بروزرسانی فروشگاه
        # -------------------------------------------------

        selected_product["quantity"] = (
            current_quantity - quantity
        )

        refresh_store()

        sale_quantity_entry.delete(
            0,
            tk.END
        )

        sale_quantity_entry.insert(
            0,
            "1"
        )

        update_total()

    # =====================================================
    # انتخاب کالا
    # =====================================================
    # =====================================================
    # انتخاب کالا
    # سوابق فروش
    # =====================================================

    def open_sales_history():

        history_window = tk.Toplevel(
            store_window
        )

        history_window.title(
            "📋 سوابق فروش"
        )

        history_window.geometry(
            "950x550"
        )

        tk.Label(
            history_window,
            text="📋 سوابق فروش",
            font=("Tahoma", 16, "bold")
        ).pack(
            pady=10
        )

        history_frame = tk.Frame(
            history_window
        )

        history_frame.pack(
            fill=tk.BOTH,
            expand=True,
            padx=10,
            pady=10
        )

        history_columns = (
            "id",
            "code",
            "name",
            "quantity",
            "price",
            "total",
            "date"
        )

        history_table = ttk.Treeview(
            history_frame,
            columns=history_columns,
            show="headings"
        )

        history_headings = {
            "id": "شماره",
            "code": "کد",
            "name": "کالا",
            "quantity": "تعداد",
            "price": "قیمت واحد",
            "total": "مبلغ کل",
            "date": "تاریخ"
        }

        for col, text in history_headings.items():

            history_table.heading(
                col,
                text=text
            )

        history_table.column("id", width=60)
        history_table.column("code", width=100)
        history_table.column("name", width=180)
        history_table.column("quantity", width=90)
        history_table.column("price", width=120)
        history_table.column("total", width=130)
        history_table.column("date", width=150)

        history_table.pack(
            fill=tk.BOTH,
            expand=True
        )

        cursor.execute("""
            SELECT id, code, name,
                   quantity, price,
                   total, sale_date
            FROM sales
            ORDER BY id DESC
        """)

        for row in cursor.fetchall():

            history_table.insert(
                "",
                tk.END,
                values=row
            )

    # =====================================================
    # درخواست خرید برای حسابداری
    # =====================================================

    def request_purchase_for_accounting():
        """ارسال درخواست خرید موسی به حسابداری؛ حتی برای کالایی که هنوز در انبار تعریف نشده است."""
        if get_active_employee() not in ("موسی", "مالک"):
            messagebox.showwarning("دسترسی", "این بخش فقط برای موسی و مالک فعال است.", parent=store_window)
            return

        win = tk.Toplevel(store_window)
        win.title("💳 درخواست خرید برای حسابداری")
        win.geometry("620x620")
        win.transient(store_window)
        win.grab_set()

        tk.Label(
            win, text="💳 درخواست خرید برای حسابداری",
            font=("Tahoma", 16, "bold")
        ).pack(pady=12)

        form = tk.Frame(win)
        form.pack(fill=tk.X, padx=25, pady=5)

        tk.Label(form, text="نوع کالا:", font=("Tahoma", 11)).grid(
            row=0, column=0, sticky="e", padx=6, pady=8
        )
        category_var = tk.StringVar(value=PRODUCT_CATEGORIES[0])
        category_combo = ttk.Combobox(
            form, textvariable=category_var,
            values=PRODUCT_CATEGORIES,
            state="readonly", width=34, font=("Tahoma", 11)
        )
        category_combo.grid(row=0, column=1, padx=6, pady=8)

        tk.Label(form, text="کالای موجود:", font=("Tahoma", 11)).grid(
            row=1, column=0, sticky="e", padx=6, pady=8
        )
        product_var = tk.StringVar()
        product_combo = ttk.Combobox(
            form, textvariable=product_var,
            state="readonly", width=34, font=("Tahoma", 11)
        )
        product_combo.grid(row=1, column=1, padx=6, pady=8)

        tk.Label(form, text="یا نام کالای جدید:", font=("Tahoma", 11)).grid(
            row=2, column=0, sticky="e", padx=6, pady=8
        )
        new_name_entry = tk.Entry(form, width=36, font=("Tahoma", 11))
        new_name_entry.grid(row=2, column=1, padx=6, pady=8)

        tk.Label(form, text="تعداد:", font=("Tahoma", 11)).grid(
            row=3, column=0, sticky="e", padx=6, pady=8
        )
        qty_entry = tk.Entry(form, width=36, font=("Tahoma", 11))
        qty_entry.grid(row=3, column=1, padx=6, pady=8)

        tk.Label(form, text="قیمت تقریبی خرید هر واحد:", font=("Tahoma", 11)).grid(
            row=4, column=0, sticky="e", padx=6, pady=8
        )
        price_entry = tk.Entry(form, width=36, font=("Tahoma", 11))
        price_entry.grid(row=4, column=1, padx=6, pady=8)

        tk.Label(form, text="واحد:", font=("Tahoma", 11)).grid(
            row=5, column=0, sticky="e", padx=6, pady=8
        )
        unit_entry = tk.Entry(form, width=36, font=("Tahoma", 11))
        unit_entry.insert(0, "عدد")
        unit_entry.grid(row=5, column=1, padx=6, pady=8)

        tk.Label(form, text="علت درخواست:", font=("Tahoma", 11)).grid(
            row=6, column=0, sticky="ne", padx=6, pady=8
        )
        reason_text = tk.Text(form, width=35, height=6, font=("Tahoma", 11))
        reason_text.grid(row=6, column=1, padx=6, pady=8)

        products_by_name = {}

        def load_products(*_):
            products_by_name.clear()
            try:
                cursor.execute(
                    "SELECT id,code,name,buy_price,unit,category "
                    "FROM products WHERE category=? ORDER BY name",
                    (category_var.get(),)
                )
                rows = cursor.fetchall()
                for pid, code, name, buy, unit, cat in rows:
                    label = f"{code} | {name}"
                    products_by_name[label] = (
                        pid, code, name, float(buy or 0), unit or "عدد", cat or category_var.get()
                    )
                product_combo["values"] = list(products_by_name.keys())
                product_var.set("")
                price_entry.delete(0, tk.END)
            except Exception as e:
                messagebox.showerror("خطا", f"خطا در خواندن کالاها:\n{e}", parent=win)

        def fill_product_data(*_):
            row = products_by_name.get(product_var.get())
            if row:
                price_entry.delete(0, tk.END)
                price_entry.insert(0, str(row[3]))
                unit_entry.delete(0, tk.END)
                unit_entry.insert(0, row[4])

        category_combo.bind("<<ComboboxSelected>>", load_products)
        product_combo.bind("<<ComboboxSelected>>", fill_product_data)
        load_products()

        def submit():
            try:
                category = category_var.get().strip()
                if category not in PRODUCT_CATEGORIES:
                    raise ValueError("نوع کالا را انتخاب کنید.")

                selected = products_by_name.get(product_var.get())
                new_name = new_name_entry.get().strip()

                if selected:
                    pid, code, name, old_buy, unit, cat = selected
                elif new_name:
                    name = new_name
                    code = ""
                    unit = unit_entry.get().strip() or "عدد"
                    old_buy = 0
                    cat = category
                else:
                    raise ValueError("یک کالای موجود را انتخاب کنید یا نام کالای جدید را وارد کنید.")

                qty = float(qty_entry.get().strip())
                price = float(price_entry.get().strip())
                reason = reason_text.get("1.0", tk.END).strip()

                if qty <= 0:
                    raise ValueError("تعداد باید بیشتر از صفر باشد.")
                if price <= 0:
                    raise ValueError("قیمت تقریبی خرید باید بیشتر از صفر باشد.")
                if not reason:
                    raise ValueError("علت درخواست را وارد کنید.")

                # برای کالای جدید کد موقت تولید می‌شود؛ کارپرداز بعداً می‌تواند
                # کالا را با کد نهایی در انبار ثبت کند.
                if not code:
                    code = generate_product_code(category)

                total = qty * price
                now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                employee = get_active_employee() or "موسی"
                request_no = f"PR-{datetime.now().strftime('%Y%m%d%H%M%S%f')}"

                # اطمینان از وجود ستون‌های لازم در DB قدیمی
                required_columns = {
                    "approval_status": "TEXT DEFAULT 'در انتظار تایید حسابداری'",
                    "approved_by": "TEXT",
                    "approved_at": "TEXT",
                    "payment_account": "TEXT",
                    "product_category": "TEXT DEFAULT 'خوراکی'"
                }
                cursor.execute("PRAGMA table_info(purchase_requests)")
                existing = {r[1] for r in cursor.fetchall()}
                for col, definition in required_columns.items():
                    if col not in existing:
                        cursor.execute(
                            f"ALTER TABLE purchase_requests ADD COLUMN {col} {definition}"
                        )

                cursor.execute("""
                    INSERT INTO purchase_requests
                    (request_no, supplier_name, product_code, product_name,
                     quantity, unit_price, total, status, request_date,
                     employee, notes, approval_status, product_category)
                    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
                """, (
                    request_no,
                    "در انتظار انتخاب کارپرداز",
                    code,
                    name,
                    qty,
                    price,
                    total,
                    "در انتظار تایید حسابداری",
                    now,
                    employee,
                    reason,
                    "در انتظار تایید حسابداری",
                    category
                ))

                request_id = cursor.lastrowid
                conn.commit()

                log_employee_activity(
                    employee,
                    "ارسال درخواست خرید برای حسابداری",
                    f"درخواست {request_id} | {category} | {name} | تعداد {qty:g} | علت: {reason}"
                )

                messagebox.showinfo(
                    "ارسال شد",
                    f"درخواست شماره {request_no} ثبت شد.\n"
                    f"وضعیت: در انتظار تأیید حسابداری\n"
                    f"نوع کالا: {category}\n"
                    f"کالا: {name}\n"
                    f"تعداد: {qty:g}",
                    parent=win
                )
                win.destroy()

            except Exception as e:
                try:
                    conn.rollback()
                except Exception:
                    pass
                messagebox.showerror(
                    "خطا در ارسال درخواست",
                    f"درخواست ثبت نشد.\n\nجزئیات خطا:\n{e}",
                    parent=win
                )

        btn = tk.Frame(win)
        btn.pack(pady=12)

        tk.Button(
            btn, text="📤 ارسال به حسابداری",
            command=submit,
            font=("Tahoma", 11, "bold"),
            width=22
        ).pack(side=tk.LEFT, padx=6)

        tk.Button(
            btn, text="بستن",
            command=win.destroy,
            width=12
        ).pack(side=tk.LEFT, padx=6)


    # =====================================================
    # خرید برای خود فروشگاه
    # =====================================================

    def store_purchase():
        """ثبت خریدی که موسی برای موجودی خود فروشگاه انجام داده است."""
        if get_active_employee() not in ("موسی", "مالک"):
            messagebox.showwarning("دسترسی", "این بخش فقط برای موسی و مالک فعال است.", parent=store_window)
            return

        win = tk.Toplevel(store_window)
        win.title("🛍 خرید برای فروشگاه")
        win.geometry("560x560")
        win.transient(store_window)
        win.grab_set()

        tk.Label(win, text="🛍 خرید برای خود فروشگاه", font=("Tahoma", 16, "bold")).pack(pady=12)
        tk.Label(win, text="این خرید پس از ثبت به موجودی فروشگاه اضافه می‌شود.", font=("Tahoma", 10)).pack(pady=2)
        form = tk.Frame(win)
        form.pack(fill=tk.X, padx=25, pady=8)

        tk.Label(form, text="نوع کالا:", font=("Tahoma", 11)).grid(row=0, column=0, sticky="e", padx=6, pady=8)
        cat_var = tk.StringVar(value="خوراکی")
        cat_combo = ttk.Combobox(form, textvariable=cat_var, values=PRODUCT_CATEGORIES, state="readonly", width=30, font=("Tahoma", 11))
        cat_combo.grid(row=0, column=1, padx=6, pady=8)

        tk.Label(form, text="کالا:", font=("Tahoma", 11)).grid(row=1, column=0, sticky="e", padx=6, pady=8)
        prod_var = tk.StringVar()
        prod_combo = ttk.Combobox(form, textvariable=prod_var, state="readonly", width=30, font=("Tahoma", 11))
        prod_combo.grid(row=1, column=1, padx=6, pady=8)

        tk.Label(form, text="تعداد:", font=("Tahoma", 11)).grid(row=2, column=0, sticky="e", padx=6, pady=8)
        qty = tk.Entry(form, width=32, font=("Tahoma", 11)); qty.grid(row=2, column=1, padx=6, pady=8)

        tk.Label(form, text="قیمت خرید هر واحد:", font=("Tahoma", 11)).grid(row=3, column=0, sticky="e", padx=6, pady=8)
        price = tk.Entry(form, width=32, font=("Tahoma", 11)); price.grid(row=3, column=1, padx=6, pady=8)

        tk.Label(form, text="فروشنده / تأمین‌کننده:", font=("Tahoma", 11)).grid(row=4, column=0, sticky="e", padx=6, pady=8)
        supplier = tk.Entry(form, width=32, font=("Tahoma", 11)); supplier.grid(row=4, column=1, padx=6, pady=8)

        tk.Label(form, text="توضیح خرید:", font=("Tahoma", 11)).grid(row=5, column=0, sticky="ne", padx=6, pady=8)
        notes = tk.Text(form, width=32, height=5, font=("Tahoma", 11)); notes.grid(row=5, column=1, padx=6, pady=8)

        items = {}
        def load(*_):
            items.clear()
            cursor.execute("SELECT id,code,name,buy_price,unit,category,COALESCE(avg_buy_price,buy_price,0) FROM products WHERE category=? ORDER BY name", (cat_var.get(),))
            for r in cursor.fetchall():
                label = f"{r[1]} | {r[2]}"
                items[label] = r
            prod_combo["values"] = list(items.keys())
            prod_var.set("")
            price.delete(0, tk.END)

        def choose(*_):
            r = items.get(prod_var.get())
            if r:
                price.delete(0, tk.END); price.insert(0, str(float(r[3] or 0)))

        cat_combo.bind("<<ComboboxSelected>>", load)
        prod_combo.bind("<<ComboboxSelected>>", choose)
        load()

        def save_purchase():
            try:
                r = items.get(prod_var.get())
                if not r: raise ValueError("کالا را انتخاب کنید.")
                q = float(qty.get().strip()); p = float(price.get().strip())
                if q <= 0: raise ValueError("تعداد باید بیشتر از صفر باشد.")
                if p <= 0: raise ValueError("قیمت خرید باید بیشتر از صفر باشد.")
                total = q * p
                now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                emp = get_active_employee() or "موسی"
                pid, code, name, old_buy, unit, cat = r
                old_qty=float(r[3] or 0)
                old_avg=float(r[6] or r[3] or 0) if len(r)>6 else float(old_buy or 0)
                new_qty=old_qty+q
                new_avg=((old_qty*old_avg)+(q*p))/new_qty if new_qty>0 else p
                post_simple("موجودی کالا", "صندوق", total,
                            description=f"خرید مستقیم {name}", ref_type="purchase", ref_id=None,
                            entry_date=now, employee=emp, commit=False)
                cursor.execute("UPDATE products SET quantity=quantity+?, buy_price=?, avg_buy_price=? WHERE id=?", (q,p,new_avg,pid))
                cursor.execute("""INSERT INTO purchases(request_id,supplier_name,product_code,product_name,quantity,unit_price,total,purchase_date,employee)
                    VALUES(NULL,?,?,?,?,?,?,?,?)""", (supplier.get().strip(),code,name,q,p,total,now,emp))
                conn.commit()
                log_employee_activity(emp, "خرید مستقیم برای فروشگاه", f"{cat} | {name} | {q:g} {unit} | مبلغ {total:g}")
                messagebox.showinfo("ثبت شد", f"خرید ثبت شد و {q:g} {unit} از «{name}» به موجودی فروشگاه اضافه شد.", parent=win)
                win.destroy()
                refresh_table()
            except Exception as e:
                conn.rollback()
                messagebox.showerror("خطا در ثبت خرید", str(e), parent=win)

        btn = tk.Frame(win); btn.pack(pady=12)
        tk.Button(btn, text="💾 ثبت خرید فروشگاه", command=save_purchase, font=("Tahoma", 11, "bold"), width=20).pack(side=tk.LEFT, padx=6)
        tk.Button(btn, text="بستن", command=win.destroy, width=12).pack(side=tk.LEFT, padx=6)

    # =====================================================
    # دکمه‌های فروشگاه
    # =====================================================

    buttons = tk.Frame(store_window)

    buttons.pack(
        fill=tk.X,
        padx=15,
        pady=10
    )

    tk.Button(
        buttons,
        text="🔍 جست‌وجو",
        font=("Tahoma", 11),
        command=refresh_store
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="🔄 بروزرسانی",
        font=("Tahoma", 11),
        command=refresh_store
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="💰 ثبت فروش",
        font=("Tahoma", 11, "bold"),
        command=register_sale
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="📋 سوابق فروش",
        font=("Tahoma", 11),
        command=open_sales_history
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="➕ تعریف جنس",
        font=("Tahoma", 11, "bold"),
        command=lambda: open_product_definition_window(store_window)
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="💳 درخواست خرید برای حسابداری",
        font=("Tahoma", 11, "bold"),
        command=request_purchase_for_accounting
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="🛍 خرید برای فروشگاه",
        font=("Tahoma", 11, "bold"),
        command=store_purchase
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="👥 مشتریان",
        font=("Tahoma", 11, "bold"),
        command=open_customers_window
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    refresh_store()
    

# =========================================================
# پنجره مشتریان
# =========================================================

def open_customers_window():

    customers_window = tk.Toplevel(window)
    customers_window.title("👥 مشتریان")
    customers_window.geometry("1000x700")

    # -------------------------
    # فرم مشتری
    # -------------------------

    form = tk.Frame(customers_window)
    form.pack(fill=tk.X, padx=10, pady=10)

    tk.Label(form, text="نام مشتری:", font=("Tahoma", 11)).grid(
        row=0, column=0, padx=5, pady=5
    )

    name_entry = tk.Entry(form, font=("Tahoma", 11), width=25)
    name_entry.grid(row=0, column=1, padx=5, pady=5)

    tk.Label(form, text="تلفن:", font=("Tahoma", 11)).grid(
        row=0, column=2, padx=5, pady=5
    )

    phone_entry = tk.Entry(form, font=("Tahoma", 11), width=20)
    phone_entry.grid(row=0, column=3, padx=5, pady=5)

    tk.Label(form, text="شهر:", font=("Tahoma", 11)).grid(
        row=1, column=0, padx=5, pady=5
    )

    city_entry = tk.Entry(form, font=("Tahoma", 11), width=25)
    city_entry.grid(row=1, column=1, padx=5, pady=5)

    tk.Label(form, text="منطقه:", font=("Tahoma", 11)).grid(
        row=1, column=2, padx=5, pady=5
    )

    region_entry = tk.Entry(form, font=("Tahoma", 11), width=20)
    region_entry.grid(row=1, column=3, padx=5, pady=5)

    tk.Label(form, text="آدرس:", font=("Tahoma", 11)).grid(
        row=2, column=0, padx=5, pady=5
    )

    address_entry = tk.Entry(form, font=("Tahoma", 11), width=60)
    address_entry.grid(
        row=2, column=1, columnspan=3,
        padx=5, pady=5
    )

    tk.Label(form, text="عرض جغرافیایی:", font=("Tahoma", 11)).grid(
        row=3, column=0, padx=5, pady=5
    )

    latitude_entry = tk.Entry(form, font=("Tahoma", 11), width=25)
    latitude_entry.grid(row=3, column=1, padx=5, pady=5)

    tk.Label(form, text="طول جغرافیایی:", font=("Tahoma", 11)).grid(
        row=3, column=2, padx=5, pady=5
    )

    longitude_entry = tk.Entry(form, font=("Tahoma", 11), width=20)
    longitude_entry.grid(row=3, column=3, padx=5, pady=5)
    # =====================================================
    # انتخاب موقعیت روی نقشه
    # =====================================================

    def choose_location_on_map():

        map_window = tk.Toplevel(
            customers_window
        )

        map_window.title(
            "📍 انتخاب موقعیت مشتری"
        )

        map_window.geometry(
            "900x650"
        )

        if tkintermapview is None:
            messagebox.showerror(
                "نقشه در دسترس نیست",
                "کتابخانه نقشه روی این سیستم نصب نیست. برنامه اصلی باز می‌شود، اما انتخاب موقعیت روی نقشه فعلاً غیرفعال است."
            )
            map_window.destroy()
            return

        map_widget = tkintermapview.TkinterMapView(
            map_window,
            width=900,
            height=650,
            corner_radius=0
        )

        map_widget.pack(
            fill=tk.BOTH,
            expand=True
        )

        # مرکز اولیه نقشه
        map_widget.set_position(
            35.6892,
            51.3890
        )

        map_widget.set_zoom(12)

        def map_click(coords):

            latitude, longitude = coords

            latitude_entry.delete(
                0,
                tk.END
            )

            latitude_entry.insert(
                0,
                str(latitude)
            )

            longitude_entry.delete(
                0,
                tk.END
            )

            longitude_entry.insert(
                0,
                str(longitude)
            )

            map_widget.set_marker(
                latitude,
                longitude,
                text="📍 مشتری"
            )

        map_widget.add_left_click_map_command(
            map_click
        )


    tk.Button(
        form,
        text="📍 انتخاب روی نقشه",
        font=("Tahoma", 11, "bold"),
        command=choose_location_on_map
    ).grid(
        row=4,
        column=0,
        columnspan=4,
        pady=8
    )


    tk.Label(
        form,
        text="توضیحات:",
        font=("Tahoma", 11)
    ).grid(
        row=5,
        column=0,
        padx=5,
        pady=5
    )

    notes_entry = tk.Entry(
        form,
        font=("Tahoma", 11),
        width=60
    )
    notes_entry.grid(
        row=5,
        column=1,
        columnspan=3,
        padx=5,
        pady=5
    )

    selected_customer_id = None

    # -------------------------
    # جدول مشتریان
    # -------------------------

    table_frame = tk.Frame(customers_window)
    table_frame.pack(
        fill=tk.BOTH,
        expand=True,
        padx=10,
        pady=10
    )

    columns = (
        "id",
        "name",
        "phone",
        "city",
        "region",
        "address",
        "latitude",
        "longitude"
    )

    table = ttk.Treeview(
        table_frame,
        columns=columns,
        show="headings"
    )

    headings = {
        "id": "شناسه",
        "name": "نام مشتری",
        "phone": "تلفن",
        "city": "شهر",
        "region": "منطقه",
        "address": "آدرس",
        "latitude": "عرض جغرافیایی",
        "longitude": "طول جغرافیایی"
    }

    for column in columns:
        table.heading(
            column,
            text=headings[column]
        )

    table.column("id", width=60)
    table.column("name", width=150)
    table.column("phone", width=120)
    table.column("city", width=100)
    table.column("region", width=100)
    table.column("address", width=250)
    table.column("latitude", width=100)
    table.column("longitude", width=100)

    table.pack(
        fill=tk.BOTH,
        expand=True
    )

    # -------------------------
    # بروزرسانی جدول
    # -------------------------

    def refresh_customers():

        for item in table.get_children():
            table.delete(item)

        cursor.execute("""
            SELECT
                id,
                name,
                phone,
                city,
                region,
                address,
                latitude,
                longitude
            FROM customers
            ORDER BY id DESC
        """)

        for row in cursor.fetchall():

            table.insert(
                "",
                tk.END,
                values=row
            )

    # -------------------------
    # انتخاب مشتری برای ویرایش
    # -------------------------

    def select_customer(event=None):

        nonlocal selected_customer_id

        selection = table.selection()

        if not selection:
            return

        values = table.item(
            selection[0]
        )["values"]

        selected_customer_id = int(values[0])

        cursor.execute("""
            SELECT name, phone, city, region, address,
                   latitude, longitude, notes
            FROM customers
            WHERE id = ?
        """, (selected_customer_id,))

        row = cursor.fetchone()

        if not row:
            return

        fields = [
            (name_entry, row[0]),
            (phone_entry, row[1]),
            (city_entry, row[2]),
            (region_entry, row[3]),
            (address_entry, row[4]),
            (latitude_entry, row[5]),
            (longitude_entry, row[6]),
            (notes_entry, row[7])
        ]

        for entry_widget, value in fields:
            entry_widget.delete(0, tk.END)
            if value is not None:
                entry_widget.insert(0, str(value))

    table.bind(
        "<Double-1>",
        select_customer
    )

    # -------------------------
    # پاک کردن فرم
    # -------------------------

    def clear_customer_form():

        nonlocal selected_customer_id
        selected_customer_id = None

        name_entry.delete(0, tk.END)
        phone_entry.delete(0, tk.END)
        city_entry.delete(0, tk.END)
        region_entry.delete(0, tk.END)
        address_entry.delete(0, tk.END)
        latitude_entry.delete(0, tk.END)
        longitude_entry.delete(0, tk.END)
        notes_entry.delete(0, tk.END)

    # -------------------------
    # ثبت مشتری
    # -------------------------

    def add_customer():

        name = name_entry.get().strip()
        phone = phone_entry.get().strip()
        city = city_entry.get().strip()
        region = region_entry.get().strip()
        address = address_entry.get().strip()
        latitude = latitude_entry.get().strip()
        longitude = longitude_entry.get().strip()
        notes = notes_entry.get().strip()

        if not name:
            messagebox.showwarning(
                "توجه",
                "نام مشتری را وارد کنید."
            )
            return

        try:

            latitude_value = (
                float(latitude)
                if latitude else None
            )

            longitude_value = (
                float(longitude)
                if longitude else None
            )

        except ValueError:

            messagebox.showerror(
                "خطا",
                "عرض و طول جغرافیایی باید عدد باشند."
            )

            return

        created_at = datetime.now().strftime(
            "%Y-%m-%d %H:%M:%S"
        )

        cursor.execute("""
            INSERT INTO customers
            (
                name,
                phone,
                address,
                city,
                region,
                latitude,
                longitude,
                notes,
                created_at
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            name,
            phone,
            address,
            city,
            region,
            latitude_value,
            longitude_value,
            notes,
            created_at
        ))

        conn.commit()
        log_employee_activity("کارمند فروشگاه", "ثبت مشتری", name)

        refresh_customers()
        clear_customer_form()

        messagebox.showinfo(
            "موفق",
            "مشتری با موفقیت ثبت شد."
        )

    # -------------------------
    # ویرایش مشتری
    # -------------------------

    def update_customer():

        nonlocal selected_customer_id

        if not selected_customer_id:
            messagebox.showwarning(
                "توجه",
                "ابتدا روی مشتری موردنظر دوبار کلیک کنید."
            )
            return

        name = name_entry.get().strip()
        phone = phone_entry.get().strip()
        city = city_entry.get().strip()
        region = region_entry.get().strip()
        address = address_entry.get().strip()
        latitude = latitude_entry.get().strip()
        longitude = longitude_entry.get().strip()
        notes = notes_entry.get().strip()

        if not name:
            messagebox.showwarning(
                "توجه",
                "نام مشتری را وارد کنید."
            )
            return

        try:
            latitude_value = float(latitude) if latitude else None
            longitude_value = float(longitude) if longitude else None
        except ValueError:
            messagebox.showerror(
                "خطا",
                "عرض و طول جغرافیایی باید عدد باشند."
            )
            return

        cursor.execute("""
            UPDATE customers
            SET name = ?,
                phone = ?,
                address = ?,
                city = ?,
                region = ?,
                latitude = ?,
                longitude = ?,
                notes = ?
            WHERE id = ?
        """, (
            name,
            phone,
            address,
            city,
            region,
            latitude_value,
            longitude_value,
            notes,
            selected_customer_id
        ))

        conn.commit()
        refresh_customers()
        clear_customer_form()

        messagebox.showinfo(
            "موفق",
            "اطلاعات مشتری با موفقیت ویرایش شد."
        )

    # -------------------------
    # دکمه‌ها
    # -------------------------

    buttons = tk.Frame(customers_window)
    buttons.pack(pady=5)

    tk.Button(
        buttons,
        text="➕ ثبت مشتری",
        font=("Tahoma", 11, "bold"),
        command=add_customer
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="✏️ ویرایش مشتری",
        font=("Tahoma", 11, "bold"),
        command=update_customer
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    tk.Button(
        buttons,
        text="🧹 پاک کردن فرم",
        font=("Tahoma", 11),
        command=clear_customer_form
    ).pack(
        side=tk.LEFT,
        padx=5
    )

    refresh_customers()

# =========================================================
# حسابداری و دفتر حساب‌ها (سیستم یکپارچه دوطرفه)
# =========================================================

def open_chart_of_accounts_window():

    coa_window = tk.Toplevel(window)
    coa_window.title("💼 حسابداری")
    coa_window.geometry("1150x750")

    notebook = ttk.Notebook(coa_window)
    notebook.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)

    # =====================================================
    # تب اول: خلاصه، ثبت هزینه و تراکنش‌ها
    # =====================================================

    summary_tab = tk.Frame(notebook)
    notebook.add(summary_tab, text="📋 ثبت و خلاصه")

    summary_frame = tk.Frame(summary_tab)
    summary_frame.pack(fill=tk.X, padx=10, pady=10)

    income_label = tk.Label(summary_frame, text="درآمد: 0", font=("Tahoma", 12, "bold"))
    income_label.pack(side=tk.LEFT, padx=15)

    expense_label = tk.Label(summary_frame, text="هزینه: 0", font=("Tahoma", 12, "bold"))
    expense_label.pack(side=tk.LEFT, padx=15)

    profit_label = tk.Label(summary_frame, text="سود خالص: 0", font=("Tahoma", 12, "bold"))
    profit_label.pack(side=tk.LEFT, padx=15)

    tk.Button(
        summary_frame,
        text="🛒 تأیید درخواست‌های خرید فروشگاه",
        font=("Tahoma", 10, "bold"),
        command=open_purchase_approval_window
    ).pack(side=tk.RIGHT, padx=10)

    # دکمه ثبت هزینه احمد در بالای صفحه حسابداری تا همیشه برای حسابدار قابل مشاهده باشد.
    tk.Button(
        summary_frame,
        text="🧾 ثبت هزینه احمد",
        font=("Tahoma", 10, "bold"),
        command=lambda: open_ahmad_expense_dialog()
    ).pack(side=tk.RIGHT, padx=10)

    form = tk.Frame(summary_tab, relief=tk.GROOVE, borderwidth=2)
    form.pack(fill=tk.X, padx=10, pady=5)

    tk.Label(form, text="نوع ثبت:", font=("Tahoma", 10)).grid(row=0, column=0, padx=5, pady=8)

    category_var = tk.StringVar(value="عمومی")
    category_combo = ttk.Combobox(
        form, textvariable=category_var,
        values=["عمومی", "اجاره", "حقوق", "آب و برق", "حمل و نقل",
                "خرید فروشگاه (موجودی)", "خرید کالا", "تبلیغات", "تعمیرات", "مالیات", "سایر"],
        width=22, state="readonly", font=("Tahoma", 10)
    )
    category_combo.grid(row=0, column=1, padx=5, pady=8)

    tk.Label(form, text="مبلغ (ریال):", font=("Tahoma", 10)).grid(row=0, column=2, padx=5, pady=8)
    amount_entry = tk.Entry(form, width=18, font=("Tahoma", 10))
    amount_entry.grid(row=0, column=3, padx=5, pady=8)

    tk.Label(form, text="پرداخت از حساب:", font=("Tahoma", 10)).grid(row=0, column=4, padx=5, pady=8)
    payment_account_var = tk.StringVar()
    payment_account_combo = ttk.Combobox(
        form, textvariable=payment_account_var, width=28,
        state="readonly", font=("Tahoma", 10)
    )
    payment_account_combo.grid(row=0, column=5, padx=5, pady=8)

    payment_accounts_map = {}

    tk.Label(form, text="توضیحات:", font=("Tahoma", 10)).grid(row=1, column=0, padx=5, pady=8)
    description_entry = tk.Entry(form, width=100, font=("Tahoma", 10))
    description_entry.grid(row=1, column=1, columnspan=5, padx=5, pady=8)

    # سمت راست صفحه: مشاهده زنده حساب‌ها و موجودی ریالی آنها
    accounts_side = tk.LabelFrame(summary_tab, text="💰 حساب‌ها و موجودی (ریال)",
                                   font=("Tahoma", 10, "bold"))
    accounts_side.pack(side=tk.RIGHT, fill=tk.Y, padx=(0, 10), pady=10)

    accounts_tree = ttk.Treeview(
        accounts_side,
        columns=("name", "type", "balance"),
        show="headings",
        height=24
    )
    accounts_tree.heading("name", text="حساب")
    accounts_tree.heading("type", text="نوع")
    accounts_tree.heading("balance", text="موجودی ریال")
    accounts_tree.column("name", width=145)
    accounts_tree.column("type", width=85)
    accounts_tree.column("balance", width=125)
    accounts_tree.pack(fill=tk.Y, expand=True, padx=5, pady=5)

    def show_side_account_statement():
        sel = accounts_tree.selection()
        if not sel:
            messagebox.showwarning("انتخاب حساب", "ابتدا یک حساب را از فهرست حساب‌ها انتخاب کنید.")
            return
        vals = accounts_tree.item(sel[0])["values"]
        acc_name = str(vals[0])

        cursor.execute("SELECT id, account_type, balance FROM accounts WHERE name=?", (acc_name,))
        acc = cursor.fetchone()
        if not acc:
            messagebox.showerror("خطا", "حساب انتخاب‌شده پیدا نشد.")
            return
        acc_id, acc_type, balance = acc

        stmt = tk.Toplevel(coa_window)
        stmt.title(f"📊 گردش حساب — {acc_name}")
        stmt.geometry("1000x620")

        top = tk.Frame(stmt)
        top.pack(fill=tk.X, padx=10, pady=10)
        tk.Label(top, text=f"حساب: {acc_name}", font=("Tahoma", 15, "bold")).pack(side=tk.LEFT, padx=8)
        tk.Label(top, text=f"نوع: {acc_type}", font=("Tahoma", 11)).pack(side=tk.LEFT, padx=12)
        bal_lbl = tk.Label(top, text=f"مانده: {float(balance or 0):,.0f} ریال", font=("Tahoma", 13, "bold"))
        bal_lbl.pack(side=tk.RIGHT, padx=8)

        summary = tk.Frame(stmt, relief=tk.GROOVE, borderwidth=1)
        summary.pack(fill=tk.X, padx=10, pady=5)
        debit_lbl = tk.Label(summary, text="جمع بدهکار: 0 ریال", font=("Tahoma", 11, "bold"))
        debit_lbl.pack(side=tk.LEFT, padx=20, pady=8)
        credit_lbl = tk.Label(summary, text="جمع بستانکار: 0 ریال", font=("Tahoma", 11, "bold"))
        credit_lbl.pack(side=tk.LEFT, padx=20, pady=8)
        count_lbl = tk.Label(summary, text="تعداد گردش: 0", font=("Tahoma", 11))
        count_lbl.pack(side=tk.RIGHT, padx=20, pady=8)

        frame = tk.Frame(stmt)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=8)
        cols = ("id", "txn", "debit", "credit", "description", "date", "employee")
        st = ttk.Treeview(frame, columns=cols, show="headings")
        heads = {"id":"شناسه", "txn":"شماره سند", "debit":"بدهکار (ریال)", "credit":"بستانکار (ریال)", "description":"شرح", "date":"تاریخ", "employee":"کارمند"}
        widths = {"id":60, "txn":170, "debit":120, "credit":120, "description":300, "date":145, "employee":100}
        for c in cols:
            st.heading(c, text=heads[c])
            st.column(c, width=widths[c])
        st.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        sb = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=st.yview)
        sb.pack(side=tk.RIGHT, fill=tk.Y)
        st.configure(yscrollcommand=sb.set)

        def refresh_side_statement():
            for item in st.get_children():
                st.delete(item)
            cursor.execute("""
                SELECT id, txn_id, debit, credit, description, entry_date, employee
                FROM ledger_entries
                WHERE account_id=? OR account_name=?
                ORDER BY id ASC
            """, (acc_id, acc_name))
            rows = cursor.fetchall()
            td = sum(float(r[2] or 0) for r in rows)
            tc = sum(float(r[3] or 0) for r in rows)
            for r in rows:
                st.insert("", tk.END, values=(r[0], r[1], f"{float(r[2] or 0):,.0f}", f"{float(r[3] or 0):,.0f}", r[4] or "", r[5] or "", r[6] or ""))
            cursor.execute("SELECT COALESCE(balance,0) FROM accounts WHERE id=?", (acc_id,))
            br = cursor.fetchone()
            bal = float(br[0] or 0) if br else 0
            bal_lbl.config(text=f"مانده: {bal:,.0f} ریال")
            debit_lbl.config(text=f"جمع بدهکار: {td:,.0f} ریال")
            credit_lbl.config(text=f"جمع بستانکار: {tc:,.0f} ریال")
            count_lbl.config(text=f"تعداد گردش: {len(rows)}")

        tk.Button(stmt, text="🔄 بروزرسانی گردش", font=("Tahoma", 10, "bold"), command=refresh_side_statement).pack(pady=8)
        refresh_side_statement()

    tk.Button(accounts_side, text="📊 مشاهده گردش حساب انتخاب‌شده", font=("Tahoma", 10, "bold"), command=show_side_account_statement).pack(fill=tk.X, padx=5, pady=(2, 5))
    accounts_tree.bind("<Double-1>", lambda event: show_side_account_statement())

    body_frame = tk.Frame(summary_tab)
    body_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(10, 0), pady=10)

    table_frame = tk.Frame(body_frame)
    table_frame.pack(fill=tk.BOTH, expand=True)

    columns = ("id", "type", "category", "amount", "description", "date")
    table = ttk.Treeview(table_frame, columns=columns, show="headings")
    headings = {"id": "شناسه", "type": "نوع", "category": "دسته", "amount": "مبلغ", "description": "توضیحات", "date": "تاریخ"}
    for col, text in headings.items():
        table.heading(col, text=text)
    table.column("id", width=60)
    table.column("type", width=80)
    table.column("category", width=120)
    table.column("amount", width=130)
    table.column("description", width=350)
    table.column("date", width=160)
    table.pack(fill=tk.BOTH, expand=True)

    def refresh_accounts_side():
        for item in accounts_tree.get_children():
            accounts_tree.delete(item)

        payment_accounts_map.clear()
        payment_values = []

        cursor.execute("""
            SELECT name, account_type, balance, normal_side
            FROM accounts
            ORDER BY id
        """)
        for name, acc_type, balance, normal_side in cursor.fetchall():
            balance = float(balance or 0)
            accounts_tree.insert(
                "", tk.END,
                values=(name, acc_type, f"{balance:,.0f}")
            )

            # حساب‌های دارایی حتی با مانده صفر یا منفی هم قابل انتخاب‌اند؛ سیستم عمداً اجازه بدهکار شدن حساب را می‌دهد.
            if acc_type == "دارایی":
                label = f"{name} | {balance:,.0f} ریال"
                payment_accounts_map[label] = name
                payment_values.append(label)

        payment_account_combo["values"] = payment_values
        if payment_values:
            if payment_account_var.get() not in payment_values:
                payment_account_var.set(payment_values[0])
        else:
            payment_account_var.set("")

    def refresh_accounting():

        for item in table.get_children():
            table.delete(item)

        cursor.execute("""
            SELECT id, entry_type, category, amount, description, entry_date
            FROM accounting
            ORDER BY id DESC
        """)
        for row in cursor.fetchall():
            display_row = list(row)
            display_row[1] = "درآمد" if row[1] == "income" else "هزینه"
            display_row[3] = f"{float(row[3]):,.0f}"
            table.insert("", tk.END, values=display_row)

        # سود و زیان از دفتر کل محاسبه می‌شود، نه جدول accounting.
        # خرید موجودی کالا هزینه نیست؛ تا زمان فروش، دارایی محسوب می‌شود.
        cursor.execute("""
            SELECT COALESCE(SUM(le.credit - le.debit), 0)
            FROM ledger_entries le
            JOIN accounts a ON a.id = le.account_id
            WHERE a.account_type = 'درآمد'
        """)
        income = float(cursor.fetchone()[0] or 0)

        cursor.execute("""
            SELECT COALESCE(SUM(le.debit - le.credit), 0)
            FROM ledger_entries le
            JOIN accounts a ON a.id = le.account_id
            WHERE a.account_type = 'هزینه'
        """)
        expense = float(cursor.fetchone()[0] or 0)

        profit = income - expense

        income_label.config(text=f"درآمد: {income:,.0f} ریال")
        expense_label.config(text=f"هزینه: {expense:,.0f} ریال")
        profit_label.config(text=f"سود خالص: {profit:,.0f} ریال")

        refresh_accounts_side()

    def clear_expense_form():
        amount_entry.delete(0, tk.END)
        description_entry.delete(0, tk.END)
        category_var.set("عمومی")
        if payment_accounts_map:
            payment_account_var.set(next(iter(payment_accounts_map)))
        else:
            payment_account_var.set("")

    def add_expense():
        amount_text = amount_entry.get().strip().replace(",", "")
        category = category_var.get().strip()
        selected_payment = payment_account_var.get().strip()
        payment_account = payment_accounts_map.get(selected_payment)

        if not amount_text:
            messagebox.showwarning("توجه", "مبلغ را به ریال وارد کنید.")
            return

        try:
            amount = float(amount_text)
        except ValueError:
            messagebox.showerror("خطا", "مبلغ باید عدد باشد.")
            return

        if amount <= 0:
            messagebox.showwarning("توجه", "مبلغ باید بیشتر از صفر باشد.")
            return

        if not payment_account:
            messagebox.showwarning(
                "انتخاب حساب",
                "ابتدا حساب پرداخت را انتخاب کنید.\nحساب‌های دارایی با هر مانده‌ای قابل انتخاب‌اند."
            )
            return

        cursor.execute("SELECT balance FROM accounts WHERE name=?", (payment_account,))
        row = cursor.fetchone()
        if not row:
            messagebox.showerror("خطا", "حساب انتخاب‌شده پیدا نشد.")
            return

        balance = float(row[0] or 0)

        entry_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        description = description_entry.get().strip() or category

        try:
            # خرید موجودی فروشگاه، هزینه جاری نیست و تا زمان فروش
            # نباید سود خالص را کاهش دهد.
            is_inventory_purchase = category == "خرید فروشگاه (موجودی)"

            if is_inventory_purchase:
                post_simple(
                    "موجودی کالا", payment_account, amount,
                    description=description,
                    ref_type="store_purchase_expense",
                    ref_id=None,
                    entry_date=entry_date,
                    employee=get_active_employee(),
                    commit=False
                )
            else:
                expense_account = EXPENSE_CATEGORY_TO_ACCOUNT.get(
                    category, "هزینه متفرقه"
                )
                post_simple(
                    expense_account, payment_account, amount,
                    description=description,
                    ref_type="expense",
                    ref_id=None,
                    entry_date=entry_date,
                    employee=get_active_employee(),
                    commit=False
                )

            # این جدول فقط سابقه ثبت را نگه می‌دارد؛ سود و زیان از دفتر کل محاسبه می‌شود.
            cursor.execute("""
                INSERT INTO accounting
                (entry_type, category, amount, description, related_sale_id, entry_date, employee)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            """, (
                "expense",
                category,
                amount,
                description,
                None,
                entry_date,
                get_active_employee()
            ))
            conn.commit()

        except Exception as e:
            conn.rollback()
            messagebox.showerror("خطا در ثبت هزینه", str(e))
            return

        clear_expense_form()
        refresh_accounting()
        refresh_coa()

        if is_inventory_purchase:
            messagebox.showinfo(
                "خرید فروشگاه ثبت شد",
                f"{amount:,.0f} ریال از حساب «{payment_account}» کم شد و "
                "در حساب «موجودی کالا» ثبت شد.\n\n"
                "این مبلغ تا زمان فروش کالا، هزینه سود و زیان محسوب نمی‌شود."
            )
        else:
            messagebox.showinfo(
                "موفق",
                f"هزینه {amount:,.0f} ریالی ثبت شد و از حساب «{payment_account}» کسر شد."
            )

    def delete_selected_entry():

        selection = table.selection()

        if not selection:
            messagebox.showwarning("توجه", "ابتدا یک تراکنش را انتخاب کنید.")
            return

        values = table.item(selection[0])["values"]
        entry_id = values[0]

        answer = messagebox.askyesno("حذف تراکنش", "آیا از حذف این تراکنش مطمئن هستید؟")

        if not answer:
            return

        # حذف مستقیم سند مالی ممنوع است؛ برای حفظ ردپای حسابداری باید سند معکوس ثبت شود.
        cursor.execute("SELECT entry_type,category,amount,description,related_sale_id,entry_date,employee FROM accounting WHERE id=?",(entry_id,))
        ar=cursor.fetchone()
        if not ar:
            messagebox.showwarning("توجه","سند پیدا نشد.")
            return
        entry_type,category,amount,desc,related_sale_id,entry_date,emp=ar
        if related_sale_id:
            messagebox.showwarning("عدم امکان","فروش ثبت‌شده را نمی‌توان از این صفحه حذف کرد؛ برای آن باید عملیات برگشت فروش ایجاد شود.")
            return
        messagebox.showinfo("کنترل حسابداری","حذف مستقیم تراکنش غیرفعال شد تا دفتر کل و گزارش‌ها ناسازگار نشوند. برای اصلاح باید سند برگشتی ثبت شود.")
        return

    buttons = tk.Frame(summary_tab)
    buttons.pack(fill=tk.X, padx=10, pady=5)

    def open_ahmad_expense_dialog():
        """فرم مستقل ثبت هزینه برای احمد؛ نوع هزینه و حساب پرداخت کاملاً مشخص است."""
        active = get_active_employee()
        if active not in ("احمد", "مالک"):
            messagebox.showwarning("دسترسی", "ثبت هزینه فقط برای احمد حسابدار یا مالک فعال است.")
            return

        dlg = tk.Toplevel(coa_window)
        dlg.title("💳 ثبت هزینه توسط حسابدار")
        dlg.geometry("620x430")
        dlg.transient(coa_window)
        dlg.grab_set()

        box = tk.LabelFrame(dlg, text="ثبت هزینه جدید", font=("Tahoma", 11, "bold"))
        box.pack(fill=tk.BOTH, expand=True, padx=15, pady=15)

        tk.Label(box, text="نوع هزینه:", font=("Tahoma", 10, "bold")).grid(row=0, column=0, sticky="e", padx=8, pady=10)
        exp_cat_var = tk.StringVar(value="عمومی")
        exp_categories = [
            "اجاره", "حقوق", "آب و برق", "حمل و نقل", "تبلیغات",
            "تعمیرات", "مالیات", "هزینه متفرقه", "سایر",
            "خرید فروشگاه (موجودی)"
        ]
        exp_cat = ttk.Combobox(box, textvariable=exp_cat_var, values=exp_categories,
                               state="readonly", width=35, font=("Tahoma", 10))
        exp_cat.grid(row=0, column=1, sticky="w", padx=8, pady=10)

        tk.Label(box, text="مبلغ (ریال):", font=("Tahoma", 10, "bold")).grid(row=1, column=0, sticky="e", padx=8, pady=10)
        exp_amount = tk.Entry(box, width=38, font=("Tahoma", 10))
        exp_amount.grid(row=1, column=1, sticky="w", padx=8, pady=10)

        tk.Label(box, text="کسر از حساب:", font=("Tahoma", 10, "bold")).grid(row=2, column=0, sticky="e", padx=8, pady=10)
        exp_account_var = tk.StringVar()
        exp_account_map = {}
        exp_account = ttk.Combobox(box, textvariable=exp_account_var, state="readonly", width=35, font=("Tahoma", 10))
        exp_account.grid(row=2, column=1, sticky="w", padx=8, pady=10)

        tk.Label(box, text="شرح هزینه:", font=("Tahoma", 10, "bold")).grid(row=3, column=0, sticky="e", padx=8, pady=10)
        exp_desc = tk.Entry(box, width=38, font=("Tahoma", 10))
        exp_desc.grid(row=3, column=1, sticky="w", padx=8, pady=10)

        balance_label = tk.Label(box, text="موجودی حساب: 0 ریال", font=("Tahoma", 10, "bold"))
        balance_label.grid(row=4, column=1, sticky="w", padx=8, pady=6)

        def refresh_exp_accounts():
            exp_account_map.clear()
            vals = []
            cursor.execute("SELECT name, balance FROM accounts WHERE account_type='دارایی' ORDER BY id")
            for name, bal in cursor.fetchall():
                bal = float(bal or 0)
                label = f"{name} | {bal:,.0f} ریال"
                exp_account_map[label] = name
                vals.append(label)
            exp_account["values"] = vals
            if vals:
                exp_account_var.set(vals[0])
                update_balance()
            else:
                exp_account_var.set("")
                balance_label.config(text="موجودی حساب: 0 ریال")

        def update_balance(*_):
            name = exp_account_map.get(exp_account_var.get())
            if not name:
                balance_label.config(text="موجودی حساب: 0 ریال")
                return
            cursor.execute("SELECT COALESCE(balance,0) FROM accounts WHERE name=?", (name,))
            row = cursor.fetchone()
            bal = float(row[0] or 0) if row else 0
            balance_label.config(text=f"موجودی حساب: {bal:,.0f} ریال")

        exp_account.bind("<<ComboboxSelected>>", update_balance)

        def save_expense():
            account_name = exp_account_map.get(exp_account_var.get())
            cat = exp_cat_var.get().strip()
            desc = exp_desc.get().strip() or cat
            raw = exp_amount.get().strip().replace(",", "")
            try:
                amount = float(raw)
            except ValueError:
                messagebox.showerror("خطا", "مبلغ باید عدد باشد.", parent=dlg)
                return
            if amount <= 0:
                messagebox.showwarning("توجه", "مبلغ باید بیشتر از صفر باشد.", parent=dlg)
                return
            if not account_name:
                messagebox.showwarning("انتخاب حساب", "یک حساب پرداخت انتخاب کنید.", parent=dlg)
                return
            cursor.execute("SELECT COALESCE(balance,0) FROM accounts WHERE name=?", (account_name,))
            row = cursor.fetchone()
            if not row:
                messagebox.showerror("خطا", "حساب انتخاب‌شده پیدا نشد.", parent=dlg)
                return
            bal = float(row[0] or 0)

            entry_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            try:
                if cat == "خرید فروشگاه (موجودی)":
                    post_simple("موجودی کالا", account_name, amount,
                                description=desc, ref_type="store_purchase_expense",
                                ref_id=None, entry_date=entry_date, employee="احمد", commit=False)
                else:
                    expense_account = EXPENSE_CATEGORY_TO_ACCOUNT.get(cat, "هزینه متفرقه")
                    post_simple(expense_account, account_name, amount,
                                description=desc, ref_type="expense", ref_id=None,
                                entry_date=entry_date, employee="احمد", commit=False)

                cursor.execute("""
                    INSERT INTO accounting
                    (entry_type, category, amount, description, related_sale_id, entry_date, employee)
                    VALUES ('expense', ?, ?, ?, NULL, ?, 'احمد')
                """, (cat, amount, desc, entry_date))
                conn.commit()
            except Exception as e:
                conn.rollback()
                messagebox.showerror("خطا در ثبت هزینه", str(e), parent=dlg)
                return

            refresh_accounting()
            refresh_coa()
            refresh_exp_accounts()
            messagebox.showinfo("ثبت شد", f"هزینه {amount:,.0f} ریال از حساب «{account_name}» ثبت شد.", parent=dlg)
            dlg.destroy()

        btns = tk.Frame(dlg)
        btns.pack(fill=tk.X, padx=15, pady=(0, 15))
        tk.Button(btns, text="💾 ثبت هزینه", font=("Tahoma", 11, "bold"), command=save_expense).pack(side=tk.LEFT, padx=5)
        tk.Button(btns, text="🔄 بروزرسانی حساب‌ها", font=("Tahoma", 10), command=refresh_exp_accounts).pack(side=tk.LEFT, padx=5)
        tk.Button(btns, text="بستن", font=("Tahoma", 10), command=dlg.destroy).pack(side=tk.RIGHT, padx=5)

        refresh_exp_accounts()

    tk.Button(buttons, text="💾 ثبت هزینه", font=("Tahoma", 10, "bold"), command=add_expense).pack(side=tk.LEFT, padx=5)
    tk.Button(buttons, text="🧾 ثبت هزینه احمد", font=("Tahoma", 10, "bold"), command=open_ahmad_expense_dialog).pack(side=tk.LEFT, padx=5)
    tk.Button(buttons, text="🔄 بروزرسانی", font=("Tahoma", 10), command=refresh_accounting).pack(side=tk.LEFT, padx=5)
    tk.Button(buttons, text="🗑️ حذف تراکنش", font=("Tahoma", 10), command=delete_selected_entry).pack(side=tk.LEFT, padx=5)
    tk.Button(buttons, text="🧹 پاک کردن فرم", font=("Tahoma", 10), command=clear_expense_form).pack(side=tk.LEFT, padx=5)

    # =====================================================
    # تب دوم: دفتر حساب‌ها (چارت حساب‌ها + دفتر روزنامه دوطرفه)
    # =====================================================

    coa_tab = tk.Frame(notebook)
    notebook.add(coa_tab, text="📒 دفتر حساب‌ها")

    tk.Label(coa_tab, text="📒 چارت حساب‌ها و مانده هر حساب", font=("Tahoma", 14, "bold")).pack(pady=8)

    # فرم افزودن حساب جدید
    add_acc_frame = tk.LabelFrame(coa_tab, text="➕ افزودن حساب جدید", font=("Tahoma", 10, "bold"))
    add_acc_frame.pack(fill=tk.X, padx=10, pady=6)

    tk.Label(add_acc_frame, text="نام حساب:", font=("Tahoma", 10)).grid(row=0, column=0, padx=5, pady=6)
    new_acc_name = tk.Entry(add_acc_frame, width=22, font=("Tahoma", 10))
    new_acc_name.grid(row=0, column=1, padx=5, pady=6)

    tk.Label(add_acc_frame, text="نوع حساب:", font=("Tahoma", 10)).grid(row=0, column=2, padx=5, pady=6)
    new_acc_type = ttk.Combobox(
        add_acc_frame, width=14, state="readonly", font=("Tahoma", 10),
        values=["دارایی", "بدهی", "سرمایه", "درآمد", "هزینه", "اشخاص", "کنترلی"]
    )
    new_acc_type.set("دارایی")
    new_acc_type.grid(row=0, column=3, padx=5, pady=6)

    tk.Label(add_acc_frame, text="ماهیت:", font=("Tahoma", 10)).grid(row=0, column=4, padx=5, pady=6)
    new_acc_side = ttk.Combobox(
        add_acc_frame, width=12, state="readonly", font=("Tahoma", 10),
        values=["بدهکار", "بستانکار"]
    )
    new_acc_side.set("بدهکار")
    new_acc_side.grid(row=0, column=5, padx=5, pady=6)

    tk.Label(add_acc_frame, text="مبلغ اولیه (ریال):", font=("Tahoma", 10)).grid(row=0, column=6, padx=5, pady=6)
    new_acc_amount = tk.Entry(add_acc_frame, width=16, font=("Tahoma", 10))
    new_acc_amount.insert(0, "0")
    new_acc_amount.grid(row=0, column=7, padx=5, pady=6)

    def add_new_account():
        name = new_acc_name.get().strip()
        acc_type = new_acc_type.get().strip()
        side_label = new_acc_side.get().strip()
        amount_text = new_acc_amount.get().strip().replace(",", "")

        if not name:
            messagebox.showwarning("توجه", "نام حساب را وارد کنید.")
            return
        if not acc_type:
            messagebox.showwarning("توجه", "نوع حساب را انتخاب کنید.")
            return

        try:
            amount = float(amount_text or "0")
        except ValueError:
            messagebox.showerror("خطا", "مبلغ اولیه باید عدد باشد.")
            return

        if amount < 0:
            messagebox.showwarning("توجه", "مبلغ اولیه نمی‌تواند منفی باشد.")
            return
        if amount > 0 and acc_type != "دارایی":
            messagebox.showwarning("مبلغ اولیه", "برای حساب‌های جدید غیر دارایی، مبلغ اولیه را صفر بگذارید و بعداً از مسیر ثبت سند حسابداری افتتاح کنید.")
            return

        normal_side = "debit" if side_label == "بدهکار" else "credit"
        try:
            cursor.execute("INSERT INTO accounts(name, account_type, balance, normal_side) VALUES(?,?,0,?)",(name,acc_type,normal_side))
            account_id=cursor.lastrowid
            if amount>0:
                post_simple(name,"سرمایه",amount,description="موجودی افتتاحیه حساب",ref_type="account_opening",ref_id=account_id,employee=get_active_employee(),commit=False)
            conn.commit()
            new_acc_name.delete(0, tk.END)
            new_acc_amount.delete(0, tk.END)
            new_acc_amount.insert(0, "0")
            refresh_coa()
            messagebox.showinfo("موفق", f"حساب «{name}» با مبلغ اولیه {amount:,.0f} ثبت شد.")
        except sqlite3.IntegrityError:
            conn.rollback()
            messagebox.showerror("خطا", "این نام حساب قبلاً وجود دارد.")
        except Exception as e:
            conn.rollback()
            messagebox.showerror("خطا", str(e))

    def add_money_to_selected_account():
        """افزایش موجودی یک حساب توسط حسابدار؛ تمام مبالغ فقط ریال هستند."""
        selection = acc_table.selection()
        if not selection:
            messagebox.showwarning("توجه", "ابتدا حساب موردنظر را از جدول انتخاب کنید.")
            return

        values = acc_table.item(selection[0])["values"]
        acc_id = int(values[0])
        acc_name = str(values[1])

        amount_text = simpledialog.askstring(
            "افزایش موجودی حساب",
            f"مبلغ افزایش موجودی حساب «{acc_name}» را به ریال وارد کنید:",
            parent=coa_window
        )
        if amount_text is None:
            return
        try:
            amount = float(str(amount_text).replace(",", "").replace("٬", "").strip())
        except ValueError:
            messagebox.showerror("خطا", "مبلغ باید فقط عدد باشد و واحد آن ریال است.")
            return
        if amount <= 0:
            messagebox.showwarning("توجه", "مبلغ باید بیشتر از صفر ریال باشد.")
            return

        desc = simpledialog.askstring(
            "شرح افزایش موجودی",
            "علت/شرح افزایش موجودی را وارد کنید:",
            initialvalue="شارژ حساب توسط حسابداری",
            parent=coa_window
        ) or "شارژ حساب توسط حسابداری"

        try:
            cursor.execute("SELECT name, account_type, normal_side, COALESCE(balance,0) FROM accounts WHERE id=?", (acc_id,))
            row = cursor.fetchone()
            if not row:
                messagebox.showerror("خطا", "حساب پیدا نشد.")
                return
            name, acc_type, normal_side, old_balance = row
            if acc_type != "دارایی":
                messagebox.showwarning("حساب نامعتبر","افزودن پول فقط برای حساب‌های دارایی انجام می‌شود؛ برای بدهی/سرمایه/درآمد/هزینه باید سند تخصصی ثبت شود.")
                return
            entry_date=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            post_simple(name,"سرمایه",amount,description=desc,ref_type="funding",ref_id=acc_id,entry_date=entry_date,employee=get_active_employee(),commit=False)
            conn.commit()
            new_balance=float(old_balance or 0)+amount
            refresh_coa()
            messagebox.showinfo("موفق", f"{amount:,.0f} ریال به حساب «{name}» اضافه شد.\nموجودی جدید: {new_balance:,.0f} ریال")
        except Exception as e:
            conn.rollback()
            messagebox.showerror("خطا", f"افزایش موجودی انجام نشد:\n{e}")

    def delete_selected_account():
        selection = acc_table.selection()
        if not selection:
            messagebox.showwarning("توجه", "ابتدا یک حساب را از جدول انتخاب کنید.")
            return

        values = acc_table.item(selection[0])["values"]
        acc_id = values[0]
        acc_name = values[1]

        # حساب‌های پایه را حذف نکن
        protected = {
            "صندوق", "بانک", "موجودی کالا", "تجهیزات", "مشتریان", "تامین کنندگان",
            "فروش کالا", "خرید کالا", "سرمایه", "سود و زیان"
        }
        if acc_name in protected:
            messagebox.showwarning("توجه", f"حساب پایه «{acc_name}» قابل حذف نیست.")
            return

        # اگر تراکنش دارد اجازه حذف نده
        cursor.execute("SELECT COUNT(*) FROM ledger_entries WHERE account_id=?", (acc_id,))
        if int(cursor.fetchone()[0] or 0) > 0:
            messagebox.showwarning("توجه", "این حساب دارای سند حسابداری است و قابل حذف نیست.")
            return

        if not messagebox.askyesno("حذف حساب", f"آیا از حذف حساب «{acc_name}» مطمئن هستید؟"):
            return

        try:
            cursor.execute("DELETE FROM accounts WHERE id=?", (acc_id,))
            conn.commit()
            refresh_coa()
            messagebox.showinfo("موفق", "حساب حذف شد.")
        except Exception as e:
            messagebox.showerror("خطا", str(e))

    tk.Button(
        add_acc_frame, text="➕ ثبت حساب", font=("Tahoma", 10, "bold"),
        command=add_new_account
    ).grid(row=0, column=8, padx=8, pady=6)

    tk.Button(
        add_acc_frame, text="🗑️ حذف حساب انتخاب‌شده", font=("Tahoma", 10),
        command=delete_selected_account
    ).grid(row=0, column=9, padx=5, pady=6)

    tk.Button(
        add_acc_frame, text="💰 افزودن پول به حساب", font=("Tahoma", 10, "bold"),
        command=add_money_to_selected_account
    ).grid(row=0, column=10, padx=5, pady=6)

    accounts_frame = tk.Frame(coa_tab)
    accounts_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

    acc_columns = ("id", "name", "type", "side", "balance")
    acc_table = ttk.Treeview(accounts_frame, columns=acc_columns, show="headings", height=10)
    acc_headings = {"id": "شناسه", "name": "نام حساب", "type": "نوع", "side": "ماهیت", "balance": "مانده"}
    for col, text in acc_headings.items():
        acc_table.heading(col, text=text)
    acc_table.column("id", width=50)
    acc_table.column("name", width=180)
    acc_table.column("type", width=100)
    acc_table.column("side", width=90)
    acc_table.column("balance", width=150)
    acc_table.pack(fill=tk.BOTH, expand=True)

    tk.Label(coa_tab, text="📖 دفتر روزنامه (آخرین سندهای دوطرفه)", font=("Tahoma", 12, "bold")).pack(pady=(10, 4))

    ledger_frame = tk.Frame(coa_tab)
    ledger_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

    ledger_columns = ("id", "txn_id", "account", "debit", "credit", "description", "date")
    ledger_table = ttk.Treeview(ledger_frame, columns=ledger_columns, show="headings", height=12)
    ledger_headings = {"id": "شناسه", "txn_id": "شماره سند", "account": "حساب", "debit": "بدهکار", "credit": "بستانکار", "description": "شرح", "date": "تاریخ"}
    for col, text in ledger_headings.items():
        ledger_table.heading(col, text=text)
    ledger_table.column("id", width=50)
    ledger_table.column("txn_id", width=160)
    ledger_table.column("account", width=120)
    ledger_table.column("debit", width=100)
    ledger_table.column("credit", width=100)
    ledger_table.column("description", width=260)
    ledger_table.column("date", width=140)
    ledger_table.pack(fill=tk.BOTH, expand=True)

    def refresh_coa():

        for item in acc_table.get_children():
            acc_table.delete(item)

        cursor.execute("""
            SELECT id, name, account_type, normal_side, balance
            FROM accounts
            ORDER BY account_type, name
        """)
        for row in cursor.fetchall():
            acc_id, acc_name, acc_type, side, balance = row
            side_label = "بدهکار" if side == "debit" else "بستانکار"
            acc_table.insert("", tk.END, values=(acc_id, acc_name, acc_type, side_label, f"{float(balance):,.0f}"))

        for item in ledger_table.get_children():
            ledger_table.delete(item)

        cursor.execute("""
            SELECT id, txn_id, account_name, debit, credit, description, entry_date
            FROM ledger_entries
            ORDER BY id DESC
            LIMIT 300
        """)
        for row in cursor.fetchall():
            entry_id, txn_id, acc_name, debit, credit, description, entry_date = row
            ledger_table.insert("", tk.END, values=(
                entry_id, txn_id, acc_name,
                f"{float(debit):,.0f}" if debit else "",
                f"{float(credit):,.0f}" if credit else "",
                description or "", entry_date
            ))

    def filter_by_selected_account():
        selection = acc_table.selection()
        if not selection:
            return
        acc_name = acc_table.item(selection[0])["values"][1]

        for item in ledger_table.get_children():
            ledger_table.delete(item)

        cursor.execute("""
            SELECT id, txn_id, account_name, debit, credit, description, entry_date
            FROM ledger_entries
            WHERE account_name = ?
            ORDER BY id DESC
            LIMIT 300
        """, (acc_name,))
        for row in cursor.fetchall():
            entry_id, txn_id, name_, debit, credit, description, entry_date = row
            ledger_table.insert("", tk.END, values=(
                entry_id, txn_id, name_,
                f"{float(debit):,.0f}" if debit else "",
                f"{float(credit):,.0f}" if credit else "",
                description or "", entry_date
            ))

    def open_selected_account_statement():
        """نمایش گردش کامل و خلاصه مالی حساب انتخاب‌شده برای حسابدار."""
        selection = acc_table.selection()
        if not selection:
            messagebox.showwarning("انتخاب حساب", "ابتدا یک حساب را از جدول انتخاب کنید.")
            return

        values = acc_table.item(selection[0])["values"]
        acc_id = int(values[0])
        acc_name = str(values[1])
        acc_type = str(values[2])
        current_balance = float(str(values[4]).replace(",", "").replace("٬", "") or 0)

        stmt = tk.Toplevel(coa_window)
        stmt.title(f"📊 گردش حساب — {acc_name}")
        stmt.geometry("1050x650")

        top = tk.Frame(stmt)
        top.pack(fill=tk.X, padx=10, pady=10)

        tk.Label(top, text=f"حساب: {acc_name}", font=("Tahoma", 14, "bold")).pack(side=tk.LEFT, padx=8)
        tk.Label(top, text=f"نوع: {acc_type}", font=("Tahoma", 11)).pack(side=tk.LEFT, padx=15)
        balance_label = tk.Label(top, text=f"مانده فعلی: {current_balance:,.0f} ریال", font=("Tahoma", 12, "bold"))
        balance_label.pack(side=tk.RIGHT, padx=8)

        summary = tk.Frame(stmt, relief=tk.GROOVE, borderwidth=1)
        summary.pack(fill=tk.X, padx=10, pady=(0, 8))
        debit_label = tk.Label(summary, text="جمع بدهکار: 0 ریال", font=("Tahoma", 11, "bold"))
        debit_label.pack(side=tk.LEFT, padx=20, pady=8)
        credit_label = tk.Label(summary, text="جمع بستانکار: 0 ریال", font=("Tahoma", 11, "bold"))
        credit_label.pack(side=tk.LEFT, padx=20, pady=8)
        count_label = tk.Label(summary, text="تعداد گردش: 0", font=("Tahoma", 11))
        count_label.pack(side=tk.RIGHT, padx=20, pady=8)

        frame = tk.Frame(stmt)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        cols = ("id", "txn", "debit", "credit", "description", "date")
        tree = ttk.Treeview(frame, columns=cols, show="headings")
        heads = {
            "id": "شناسه", "txn": "شماره سند", "debit": "بدهکار (ریال)",
            "credit": "بستانکار (ریال)", "description": "شرح", "date": "تاریخ"
        }
        widths = {"id": 60, "txn": 180, "debit": 125, "credit": 125, "description": 330, "date": 150}
        for col in cols:
            tree.heading(col, text=heads[col])
            tree.column(col, width=widths[col])
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scroll = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tree.yview)
        scroll.pack(side=tk.RIGHT, fill=tk.Y)
        tree.configure(yscrollcommand=scroll.set)

        def refresh_statement():
            for item in tree.get_children():
                tree.delete(item)

            cursor.execute("""
                SELECT id, txn_id, debit, credit, description, entry_date
                FROM ledger_entries
                WHERE account_id = ? OR account_name = ?
                ORDER BY id ASC
            """, (acc_id, acc_name))
            rows = cursor.fetchall()
            total_debit = sum(float(r[2] or 0) for r in rows)
            total_credit = sum(float(r[3] or 0) for r in rows)

            for rid, txn_id, debit, credit, description, entry_date in rows:
                tree.insert("", tk.END, values=(
                    rid, txn_id,
                    f"{float(debit or 0):,.0f}" if debit else "",
                    f"{float(credit or 0):,.0f}" if credit else "",
                    description or "", entry_date or ""
                ))

            cursor.execute("SELECT COALESCE(balance,0) FROM accounts WHERE id=?", (acc_id,))
            bal_row = cursor.fetchone()
            balance = float(bal_row[0] or 0) if bal_row else current_balance
            balance_label.config(text=f"مانده فعلی: {balance:,.0f} ریال")
            debit_label.config(text=f"جمع بدهکار: {total_debit:,.0f} ریال")
            credit_label.config(text=f"جمع بستانکار: {total_credit:,.0f} ریال")
            count_label.config(text=f"تعداد گردش: {len(rows)}")

        tk.Button(stmt, text="🔄 بروزرسانی گردش", font=("Tahoma", 10, "bold"),
                  command=refresh_statement).pack(pady=8)
        refresh_statement()

    acc_table.bind("<<TreeviewSelect>>", lambda event: filter_by_selected_account())
    acc_table.bind("<Double-1>", lambda event: open_selected_account_statement())

    coa_buttons = tk.Frame(coa_tab)
    coa_buttons.pack(fill=tk.X, padx=10, pady=5)
    tk.Button(coa_buttons, text="🔄 بروزرسانی / نمایش همه", font=("Tahoma", 10), command=refresh_coa).pack(side=tk.LEFT, padx=5)
    tk.Button(coa_buttons, text="📊 گردش حساب انتخاب‌شده", font=("Tahoma", 10, "bold"),
              command=open_selected_account_statement).pack(side=tk.LEFT, padx=5)

    refresh_accounting()
    refresh_coa()


# =========================================================
# 👔 مدیر هوش مصنوعی و نظارت کارکنان
# =========================================================

def get_ai_profile():
    cursor.execute("SELECT owner_name, role, mission, rules FROM ai_profile WHERE id = 1")
    row = cursor.fetchone()
    if not row:
        return {
            "owner_name": "مالک و خالق برنامه",
            "role": "مدیر ارشد و ناظر کل سیستم",
            "mission": "نظارت بر کل فروشگاه",
            "rules": ""
        }
    core = get_core_memory()
    return {
        "owner_name": core.get("creator_name", row[0]),
        "creator_national_id": core.get("creator_national_id", CREATOR_NATIONAL_ID),
        "role": row[1],
        "mission": row[2],
        "rules": row[3] or ""
    }


def save_email_insight(account, sender, subject, insight, importance="medium"):
    try:
        cursor.execute("""
            INSERT INTO ai_email_insights
            (email_account, sender, subject, insight, importance, created_at)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (
            str(account or "")[:320],
            str(sender or "")[:500],
            str(subject or "")[:500],
            str(insight or "")[:4000],
            str(importance or "medium")[:30],
            datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ))
        conn.commit()
    except Exception:
        pass


def create_manager_task(title, description, employee, source="manager", priority="medium", due_date=""):
    cursor.execute("""
        INSERT INTO manager_tasks
        (title, description, assigned_employee, source, priority, status, due_date, created_at)
        VALUES (?, ?, ?, ?, ?, 'open', ?, ?)
    """, (
        str(title).strip()[:200],
        str(description or "").strip()[:1200],
        str(employee).strip(),
        str(source).strip(),
        str(priority).strip(),
        str(due_date or "").strip(),
        datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    ))
    conn.commit()
    return int(cursor.lastrowid)


def seed_default_employee_tasks():
    """ساخت وظایف پایه کارکنان؛ فقط اگر نمونه باز مشابه وجود نداشته باشد."""
    defaults = [
        ("بررسی روزانه موجودی انبار", "موجودی کالاها را بررسی کن؛ کالاهای کم‌موجودی یا منفی را شناسایی و گزارش کن.", "کارمند انبار", "system_seed", "high"),
        ("بررسی فروش و مشتریان امروز", "فروش‌های امروز را بررسی کن؛ فروش بدون مشتری و موارد غیرعادی را گزارش کن.", "کارمند فروشگاه", "system_seed", "medium"),
        ("بررسی حسابداری امروز", "درآمد، هزینه و ثبت‌های مالی امروز را بررسی کن و اختلاف‌های احتمالی را گزارش کن.", "کارمند حسابداری", "system_seed", "high"),
        ("پیگیری درخواست‌های خرید", "درخواست‌های خرید در انتظار را بررسی کن و موارد معوق را گزارش و پیگیری کن.", "کارمند کارپرداز", "system_seed", "medium"),
    ]
    created = 0
    for title, description, employee, source, priority in defaults:
        cursor.execute("""
            SELECT id FROM manager_tasks
            WHERE assigned_employee=? AND title=? AND status != 'done'
            LIMIT 1
        """, (employee, title))
        if cursor.fetchone():
            continue
        create_manager_task(title, description, employee, source=source, priority=priority)
        created += 1
    return created

def get_open_manager_tasks(employee=None, limit=50):
    """سازگاری قدیمی: فقط وظایف باز را برمی‌گرداند."""
    if employee:
        cursor.execute("""
            SELECT id, title, description, assigned_employee, source, priority, status, due_date, created_at
            FROM manager_tasks
            WHERE status != 'done' AND assigned_employee = ?
            ORDER BY CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, id DESC
            LIMIT ?
        """, (employee, int(limit)))
    else:
        cursor.execute("""
            SELECT id, title, description, assigned_employee, source, priority, status, due_date, created_at
            FROM manager_tasks
            WHERE status != 'done'
            ORDER BY CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, id DESC
            LIMIT ?
        """, (int(limit),))
    return cursor.fetchall()


def get_all_manager_tasks(employee=None, status_filter="all", limit=500):
    """تمام وظایف کارکنان را برای مرکز وظایف مدیر برمی‌گرداند؛ شامل وظایف خودکار و انجام‌شده."""
    where = []
    params = []
    if employee and employee != "همه کارکنان":
        where.append("assigned_employee = ?")
        params.append(employee)
    if status_filter and status_filter != "all":
        where.append("status = ?")
        params.append(status_filter)

    sql = """
        SELECT id, title, description, assigned_employee, source, priority, status,
               due_date, created_at, completed_at, manager_note, started_at,
               execution_result, execution_mode, last_error
        FROM manager_tasks
    """
    if where:
        sql += " WHERE " + " AND ".join(where)
    sql += """
        ORDER BY
            CASE status
                WHEN 'in_progress' THEN 0
                WHEN 'waiting_approval' THEN 1
                WHEN 'open' THEN 2
                WHEN 'failed' THEN 3
                WHEN 'done' THEN 4
                ELSE 5
            END,
            CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END,
            id DESC
        LIMIT ?
    """
    params.append(int(limit))
    cursor.execute(sql, tuple(params))
    return cursor.fetchall()


def get_manager_task_counts(employee=None):
    """تعداد وظایف را بر اساس وضعیت برمی‌گرداند."""
    where = []
    params = []
    if employee and employee != "همه کارکنان":
        where.append("assigned_employee = ?")
        params.append(employee)
    sql = "SELECT status, COUNT(*) FROM manager_tasks"
    if where:
        sql += " WHERE " + " AND ".join(where)
    sql += " GROUP BY status"
    cursor.execute(sql, tuple(params))
    result = {"open": 0, "in_progress": 0, "waiting_approval": 0, "failed": 0, "done": 0}
    for status, count in cursor.fetchall():
        result[str(status)] = int(count)
    result["total"] = sum(result.values())
    return result

def update_manager_task_status(task_id, status, result="", error="", execution_mode=None):
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    completed_at = now if status == 'done' else None
    started_at = now if status == 'in_progress' else None
    if execution_mode is None:
        cursor.execute("SELECT execution_mode FROM manager_tasks WHERE id=?", (int(task_id),))
        rr = cursor.fetchone()
        execution_mode = rr[0] if rr and rr[0] else 'manual'
    cursor.execute("""
        UPDATE manager_tasks
        SET status = ?, completed_at = COALESCE(?, completed_at),
            started_at = COALESCE(?, started_at), execution_result = ?,
            last_error = ?, execution_mode = ?
        WHERE id = ?
    """, (str(status), completed_at, started_at, str(result or '')[:8000], str(error or '')[:3000], str(execution_mode), int(task_id)))
    conn.commit()

def _task_row(task_id):
    cursor.execute("""
        SELECT id,title,description,assigned_employee,source,priority,status,due_date,created_at,
               completed_at,manager_note,started_at,execution_result,execution_mode,last_error
        FROM manager_tasks WHERE id=?
    """, (int(task_id),))
    return cursor.fetchone()

def _extract_product_name_from_task(title, description):
    text = f"{title or ''} {description or ''}"
    m = re.search(r"(?:کمبود موجودی|موجودی منفی)\s*[:：]\s*(.+?)(?:$|\n)", text)
    if m:
        return m.group(1).strip()
    return ''

def _employee_task_action(task_id, employee):
    row = _task_row(task_id)
    if not row:
        raise ValueError('وظیفه پیدا نشد.')
    (_id,title,description,assigned,source,priority,status,due,created,completed_at,manager_note,started_at,execution_result,execution_mode,last_error) = row
    if str(assigned) != str(employee):
        raise PermissionError('این وظیفه به این کارمند اختصاص داده نشده است.')
    if status == 'done':
        return 'این وظیفه قبلاً انجام شده است.'

    update_manager_task_status(task_id, 'in_progress', execution_mode='auto')
    try:
        title_l = str(title or '')
        desc_l = str(description or '')

        # ۱) کمبود موجودی: ایجاد خودکار درخواست خرید برای حسابداری
        if title_l.startswith('کمبود موجودی:') and employee in ('کارمند انبار','علی'):
            product_name = _extract_product_name_from_task(title_l, desc_l)
            cursor.execute("SELECT id,code,name,quantity,buy_price,unit,category FROM products WHERE name=? COLLATE NOCASE LIMIT 1", (product_name,))
            prod = cursor.fetchone()
            if not prod:
                raise ValueError(f'کالای «{product_name}» پیدا نشد؛ درخواست خرید خودکار ساخته نشد.')
            pid,code,name,quantity,buy_price,unit,category = prod
            target_qty = max(10.0, float(quantity or 0) + 10.0)
            request_qty = max(1.0, round(target_qty - float(quantity or 0), 2))
            unit_price = float(buy_price or 0)
            if unit_price <= 0:
                result = f'کالای «{name}» کمبود موجودی دارد، اما قیمت خرید آن ثبت نشده است. نیاز به اقدام مدیر/کارپرداز دارد.'
                update_manager_task_status(task_id, 'waiting_approval', result=result, execution_mode='auto')
                log_employee_activity(employee, 'اجرای وظیفه', result)
                return result
            total = round(request_qty * unit_price, 2)
            now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            request_no = f"AUTO-{datetime.now().strftime('%Y%m%d%H%M%S%f')}"
            cursor.execute("""
                INSERT INTO purchase_requests
                (request_no,supplier_name,product_code,product_name,quantity,unit_price,total,status,request_date,employee,notes,approval_status,product_category,requested_by,requester)
                VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
            """, (request_no,'در انتظار انتخاب کارپرداز',code,name,request_qty,unit_price,total,'در انتظار تایید حسابداری',now,employee,
                  f'درخواست خودکار از وظیفه مدیر؛ موجودی فعلی {float(quantity or 0):g} {unit}',
                  'در انتظار تایید حسابداری',category or 'خوراکی',employee,employee))
            req_id = int(cursor.lastrowid)
            conn.commit()
            result = f'برای «{name}» درخواست خرید خودکار شماره {req_id} ساخته شد: {request_qty:g} {unit} × {unit_price:,.0f} ریال = {total:,.0f} ریال. برای احمد ارسال شد.'
            update_manager_task_status(task_id, 'done', result=result, execution_mode='auto')
            log_employee_activity(employee, 'اجرای وظیفه و ایجاد درخواست خرید', f'وظیفه {task_id} | درخواست {req_id} | {name} | {total:,.0f} ریال')
            return result

        # ۲) بررسی فروش بدون مشتری: گزارش واقعی تولید می‌کند؛ اصلاح اطلاعات حدسی نیست.
        if 'فروش‌های بدون مشتری' in title_l and employee in ('کارمند فروشگاه','موسی'):
            today = datetime.now().strftime('%Y-%m-%d')
            cursor.execute("SELECT id, name, total, sale_date FROM sales WHERE substr(sale_date,1,10)=? AND (customer_id IS NULL OR customer_id=0) ORDER BY id DESC LIMIT 30", (today,))
            rows = cursor.fetchall()
            result = 'گزارش فروش‌های بدون مشتری امروز:\n' + ('\n'.join(f'فروش #{r[0]} | {r[1]} | {float(r[2] or 0):,.0f} ریال' for r in rows) if rows else 'موردی پیدا نشد.')
            update_manager_task_status(task_id, 'waiting_approval' if rows else 'done', result=result, execution_mode='auto')
            log_employee_activity(employee, 'بررسی فروش‌های بدون مشتری', f'وظیفه {task_id} | تعداد {len(rows)}')
            return result

        # ۳) اختلاف فروش و حسابداری: گزارش واقعی
        if 'اختلاف فروش و حسابداری' in title_l and employee in ('کارمند حسابداری','احمد'):
            today = datetime.now().strftime('%Y-%m-%d')
            cursor.execute("SELECT COALESCE(SUM(total),0) FROM sales WHERE substr(sale_date,1,10)=?", (today,)); sales_total=float(cursor.fetchone()[0] or 0)
            cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='income' AND substr(entry_date,1,10)=?", (today,)); income_total=float(cursor.fetchone()[0] or 0)
            diff=sales_total-income_total
            result=f'بررسی حسابداری امروز: فروش {sales_total:,.0f} ریال | درآمد ثبت‌شده {income_total:,.0f} ریال | اختلاف {diff:,.0f} ریال.'
            update_manager_task_status(task_id, 'done' if abs(diff)<=0.01 else 'waiting_approval', result=result, execution_mode='auto')
            log_employee_activity(employee, 'بررسی اختلاف فروش و حسابداری', result)
            return result

        # ۴) هزینه بیشتر از درآمد: گزارش واقعی
        if 'هزینه‌های امروز' in title_l and employee in ('کارمند حسابداری','احمد'):
            today=datetime.now().strftime('%Y-%m-%d')
            cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='income' AND substr(entry_date,1,10)=?", (today,)); inc=float(cursor.fetchone()[0] or 0)
            cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='expense' AND substr(entry_date,1,10)=?", (today,)); exp=float(cursor.fetchone()[0] or 0)
            result=f'گزارش هزینه امروز: درآمد {inc:,.0f} ریال | هزینه {exp:,.0f} ریال | خالص {inc-exp:,.0f} ریال.'
            update_manager_task_status(task_id, 'done', result=result, execution_mode='auto')
            log_employee_activity(employee, 'بررسی هزینه‌های امروز', result)
            return result

        # ۵) درخواست خرید معوق: گزارش و پیگیری ثبت‌شده
        if 'درخواست‌های خرید معوق' in title_l and employee in ('کارمند کارپرداز','امید'):
            cursor.execute("SELECT id,product_name,quantity,status,request_date FROM purchase_requests WHERE status='در انتظار' AND date(request_date)<=date('now','-2 day') ORDER BY id")
            rows=cursor.fetchall()
            result='درخواست‌های خرید معوق:\n'+('\n'.join(f'#{r[0]} | {r[1]} | {r[2]:g} | {r[3]} | {r[4]}' for r in rows) if rows else 'موردی وجود ندارد.')
            update_manager_task_status(task_id, 'done', result=result, execution_mode='auto')
            log_employee_activity(employee, 'پیگیری درخواست‌های خرید معوق', f'وظیفه {task_id} | تعداد {len(rows)}')
            return result

        # وظیفه عمومی: AI برنامه اقدام می‌سازد، اما تغییر حساس را خودکار اجرا نمی‌کند.
        context = get_task_summary()
        prompt = (f'کارمند {employee} این وظیفه را اجرا می‌کند.\nعنوان: {title_l}\nتوضیح: {desc_l}\n'
                  'بر اساس داده واقعی سیستم، حداکثر 5 اقدام عملی انجام‌شدنی پیشنهاد بده. اگر اقدامی نیازمند تغییر مالی، حذف داده یا تصمیم مالک است، آن را فقط به عنوان نیازمند تأیید مشخص کن. چیزی را حدس نزن.\n'
                  f'وظایف باز: {context}')
        result = _call_local_ai(prompt, num_predict=350, timeout=120)
        update_manager_task_status(task_id, 'waiting_approval', result=result, execution_mode='ai_assisted')
        log_employee_activity(employee, 'تحلیل و اجرای کمکی وظیفه', f'وظیفه {task_id} | {result[:700]}')
        return result
    except Exception as exc:
        update_manager_task_status(task_id, 'open', error=str(exc), execution_mode='auto')
        raise

def execute_employee_task(task_id, employee):
    return _employee_task_action(task_id, employee)

def get_employee_task_rows(employee, limit=50):
    role = normalize_employee_role(employee)
    rows = list(get_open_manager_tasks(employee=role, limit=limit))
    if employee != role:
        extra = get_open_manager_tasks(employee=employee, limit=limit)
        seen = {r[0] for r in rows}
        for r in extra:
            if r[0] not in seen:
                rows.append(r)
    return rows


def get_task_summary():
    cursor.execute("""
        SELECT assigned_employee, status, COUNT(*)
        FROM manager_tasks
        GROUP BY assigned_employee, status
        ORDER BY assigned_employee, status
    """)
    rows=cursor.fetchall()
    if not rows:
        return "موردی ثبت نشده"
    return "\n".join(f"{e}: {st} = {cnt}" for e, st, cnt in rows)


def auto_create_tasks_from_email_insights():
    """از تحلیل ایمیل‌های مهم، در صورت نبودن وظیفه مشابه، کار ایجاد می‌کند."""
    cursor.execute("""
        SELECT id, sender, subject, insight, importance
        FROM ai_email_insights
        ORDER BY id DESC
        LIMIT 10
    """)
    rows=cursor.fetchall()
    created=0
    for iid, sender, subject, insight, importance in rows:
        text=f"{subject} {insight}".lower()
        if any(k in text for k in ["موجودی", "انبار", "کالا", "تحویل", "ارسال"]):
            employee="کارمند انبار"
        elif any(k in text for k in ["فروش", "مشتری", "سفارش", "قیمت"]):
            employee="کارمند فروشگاه"
        elif any(k in text for k in ["فاکتور", "پرداخت", "هزینه", "حساب", "بدهی", "مالی"]):
            employee="کارمند حسابداری"
        else:
            continue

        title=f"پیگیری ایمیل: {subject[:120]}"
        cursor.execute("""
            SELECT COUNT(*) FROM manager_tasks
            WHERE title = ? AND assigned_employee = ? AND status != 'done'
        """, (title, employee))
        if int(cursor.fetchone()[0] or 0) == 0:
            create_manager_task(
                title,
                f"فرستنده: {sender}\nتحلیل مدیر: {insight}",
                employee,
                source="email",
                priority="high" if importance == "high" else "medium"
            )
            created += 1
    return created


def get_recent_email_insights(limit=8):
    cursor.execute("""
        SELECT sender, subject, insight, importance, created_at
        FROM ai_email_insights
        ORDER BY id DESC
        LIMIT ?
    """, (int(limit),))
    rows = cursor.fetchall()
    if not rows:
        return "موردی ثبت نشده"
    out = []
    for sender, subject, insight, importance, created_at in rows:
        out.append(
            f"فرستنده: {sender} | موضوع: {subject} | اهمیت: {importance} | تاریخ: {created_at}\n{insight}"
        )
    return "\n\n---\n\n".join(out)


def _call_local_ai(prompt, num_predict=120, timeout=90):
    response = requests.post(
        "http://localhost:11434/api/chat",
        json={
            "model": get_ai_model(),
            "messages": [
                {"role": "system", "content": "تو مدیر و ناظر داخلی یک فروشگاه هستی."},
                {"role": "user", "content": prompt}
            ],
            "stream": False,
            "keep_alive": "2m",
            "options": {"num_predict": num_predict, "temperature": 0.15, "num_ctx": 1024, "num_thread": 4}
        },
        timeout=timeout
    )
    response.raise_for_status()
    return response.json()["message"]["content"]


# =========================================================
# ارتقای مدل (Ollama)
# =========================================================

def get_ai_model():
    try:
        cursor.execute("SELECT value FROM app_settings WHERE key='ai_model'")
        row = cursor.fetchone()
        return row[0] if row and row[0] else 'qwen2.5:3b'
    except Exception:
        return 'qwen2.5:3b'


def set_ai_model(name):
    cursor.execute(
        "INSERT OR REPLACE INTO app_settings(key,value) VALUES('ai_model',?)",
        (str(name),)
    )
    conn.commit()
    remember_ai_learning(
        "ارتقای مدل",
        f"مدل هوش مصنوعی به «{name}» تغییر کرد.",
        source="model_upgrade", confidence=1.0
    )



# مدل پیش‌فرض سریع محلی
try:
    cursor.execute("SELECT value FROM app_settings WHERE key='ai_model'")
    _row = cursor.fetchone()
    if not _row or not _row[0] or _row[0] in ('llama3.2', 'llama3', 'llama2'):
        cursor.execute("INSERT OR REPLACE INTO app_settings(key,value) VALUES('ai_model','qwen2.5:3b')")
        conn.commit()
except Exception:
    pass

def list_ollama_models():
    """لیست مدل‌های نصب‌شده روی Ollama محلی را برمی‌گرداند: [(name, size_bytes, param_size), ...]"""
    try:
        r = requests.get('http://localhost:11434/api/tags', timeout=10)
        r.raise_for_status()
        data = r.json()
    except Exception as e:
        raise ValueError(f"اتصال به Ollama برقرار نشد (مطمئن شو Ollama در حال اجراست): {e}")

    models = []
    for m in data.get('models', []):
        name = m.get('name') or m.get('model') or ''
        size = m.get('size', 0) or 0
        param_size = (m.get('details') or {}).get('parameter_size', '') or ''
        if name:
            models.append((name, size, param_size))
    return models


# =========================================================
# یادگیری رفتاری و خوداصلاحی قوانین AI
# =========================================================

def update_ai_rules(new_rules, reason=""):
    old_profile = get_ai_profile()
    new_rules = str(new_rules).strip()[:4000]

    cursor.execute(
        "UPDATE ai_profile SET rules=?, updated_at=? WHERE id=1",
        (new_rules, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    )
    conn.commit()

    remember_ai_learning(
        "خوداصلاحی قوانین",
        f"قوانین قبلی: {old_profile['rules']}\n\nقوانین جدید: {new_rules}\n\nدلیل: {reason}",
        source="self_upgrade", confidence=0.7
    )


def evolve_ai_rules_from_experience():
    """بر اساس یادگیری‌ها و سوابق مدیریتی اخیر، قوانین رفتاری AI را اصلاح می‌کند."""
    profile = get_ai_profile()
    recent_learning = get_recent_ai_learning(15)
    history = get_manager_history(5)

    prompt = (
        "تو مغز مدیریتی این فروشگاه هستی و می‌خواهی بر اساس تجربه‌های اخیر، "
        "قوانین رفتاری خودت را اصلاح کنی.\n\n"
        f"مأموریت فعلی: {profile['mission']}\n"
        f"قوانین فعلی: {profile['rules']}\n\n"
        f"یادگیری‌های اخیر:\n{recent_learning or 'موردی ثبت نشده'}\n\n"
        f"سوابق مدیریتی اخیر:\n{history or 'موردی ثبت نشده'}\n\n"
        "بر اساس این تجربه‌ها، نسخه اصلاح‌شده و کوتاه (حداکثر ۸ خط) از قوانین رفتاری را فقط "
        "به‌صورت متن ساده بنویس. قانون‌های خوب قبلی را حذف نکن، فقط نکات جدید و مهم را اضافه یا "
        "اصلاح کن. هیچ‌گاه اختیاراتی بیشتر از حد فعلی برای خودت تعریف نکن. چیزی جز خود قوانین ننویس."
    )

    new_rules = _call_local_ai(prompt, num_predict=200, timeout=180)
    update_ai_rules(new_rules, reason="خوداصلاحی خودکار بر اساس تجربه")
    return new_rules


# =========================================================
# 🧑‍💻 عامل برنامه‌نویس خودکار AI
# =========================================================

def _get_source_path():
    return os.path.abspath(__file__)

def _read_program_source():
    with open(_get_source_path(), 'r', encoding='utf-8') as f:
        return f.read()

def _get_top_level_function_outline(source):
    import ast
    tree = ast.parse(source)
    lines = source.splitlines()
    result = []
    for node in tree.body:
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
            end = getattr(node, 'end_lineno', node.lineno)
            first = lines[node.lineno - 1].strip() if 0 < node.lineno <= len(lines) else ''
            result.append({'name': node.name, 'start': node.lineno, 'end': end, 'signature': first[:220]})
    return result

def _extract_top_level_function(source, function_name):
    import ast
    tree = ast.parse(source)
    lines = source.splitlines(True)
    for node in tree.body:
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == function_name:
            start = node.lineno - 1
            end = getattr(node, 'end_lineno', node.lineno)
            return ''.join(lines[start:end]), start, end
    raise ValueError(f'تابع «{function_name}» در فایل پیدا نشد.')

def _extract_json_object(text):
    text = str(text or '').strip()
    try:
        return json.loads(text)
    except Exception:
        pass
    match = re.search(r'\{.*\}', text, flags=re.S)
    if not match:
        raise ValueError('پاسخ عامل برنامه‌نویس JSON معتبر نداشت.')
    return json.loads(match.group(0))

def _call_code_agent(prompt, timeout=300):
    response = requests.post(
        'http://localhost:11434/api/chat',
        json={
            'model': get_ai_model(),
            'messages': [
                {'role': 'system', 'content': 'تو عامل برنامه‌نویس یک برنامه Python/Tkinter/SQLite هستی. کد را فقط وقتی پیشنهاد بده که با ساختار فعلی سازگار باشد. هیچ‌وقت اطلاعات مالی یا حافظه هویتی را حذف نکن. برای مرحله تحلیل، JSON معتبر بده. برای مرحله تولید کد، فقط کد تابع خواسته‌شده را بده.'},
                {'role': 'user', 'content': prompt}
            ],
            'stream': False,
            'keep_alive': '10m',
            'options': {'num_predict': 1200, 'temperature': 0.05}
        },
        timeout=timeout
    )
    response.raise_for_status()
    return response.json()['message']['content']

def _validate_python_file(path):
    import subprocess
    proc = subprocess.run([sys.executable, '-m', 'py_compile', path], capture_output=True, text=True, timeout=60)
    if proc.returncode != 0:
        return False, (proc.stderr or proc.stdout or 'خطای نامشخص در py_compile')
    return True, 'OK'

def self_improve_code(topic, owner_approved=True):
    if not owner_approved:
        raise PermissionError('فقط مالک سیستم می‌تواند خوداصلاحی کد را اجرا کند.')
    source = _read_program_source()
    outline = _get_top_level_function_outline(source)
    if not outline:
        raise ValueError('هیچ تابع سطح اصلی برای اصلاح پیدا نشد.')
    outline_text = '\n'.join(f"- {x['name']} | خطوط {x['start']}-{x['end']} | {x['signature']}" for x in outline)
    topic = (topic or '').strip() or 'بهبود کلی پایداری و خطایابی برنامه'
    select_prompt = """موضوع اصلاح: %s

فهرست توابع برنامه:
%s

فقط یک تابع مناسب انتخاب کن. پاسخ فقط JSON باشد:
{"functions":["نام_تابع"],"reason":"دلیل کوتاه"}
""" % (topic, outline_text)
    selection = _extract_json_object(_call_code_agent(select_prompt, timeout=180))
    names = [n for n in (selection.get('functions') or []) if any(x['name'] == n for x in outline)][:1]
    if not names:
        raise ValueError('عامل برنامه‌نویس نتوانست تابع مناسب را انتخاب کند.')
    function_name = names[0]
    old_function, start, end = _extract_top_level_function(source, function_name)
    code_prompt = """موضوع: %s
نام تابعی که باید اصلاح شود: %s

کد فعلی تابع:
```python
%s
```

فقط همین تابع را اصلاح کن. رفتارهای فعلی غیرمرتبط را حفظ کن. خروجی فقط کد کامل همین تابع باشد؛ بدون ``` و بدون توضیح.
""" % (topic, function_name, old_function)
    new_function = _call_code_agent(code_prompt, timeout=300).strip()
    if new_function.startswith('```'):
        new_function = re.sub(r'^```(?:python)?\s*', '', new_function, flags=re.I)
        new_function = re.sub(r'\s*```$', '', new_function).strip()
    import ast
    parsed = ast.parse(new_function)
    defs = [n for n in parsed.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))]
    if len(defs) != 1 or defs[0].name != function_name:
        raise ValueError('کد تولیدشده یک تابع معتبر با نام موردنظر نیست.')
    lines = source.splitlines(True)
    candidate = ''.join(lines[:start]) + new_function.rstrip() + '\n' + ''.join(lines[end:])
    candidate_path = _get_source_path() + '.selftest.py'
    backup_dir = os.path.join(BASE_DIR, 'ai_code_backups')
    os.makedirs(backup_dir, exist_ok=True)
    with open(candidate_path, 'w', encoding='utf-8') as f:
        f.write(candidate)
    ok, detail = _validate_python_file(candidate_path)
    try:
        os.remove(candidate_path)
    except Exception:
        pass
    if not ok:
        raise ValueError('نسخه پیشنهادی در تست نحوی شکست خورد:\n' + detail[-4000:])
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    backup_path = os.path.join(backup_dir, f'ai_local_{timestamp}.py.bak')
    with open(backup_path, 'w', encoding='utf-8') as f:
        f.write(source)
    temp_path = _get_source_path() + '.new'
    with open(temp_path, 'w', encoding='utf-8') as f:
        f.write(candidate)
    os.replace(temp_path, _get_source_path())
    ok, detail = _validate_python_file(_get_source_path())
    if not ok:
        with open(backup_path, 'r', encoding='utf-8') as f:
            previous = f.read()
        with open(_get_source_path(), 'w', encoding='utf-8') as f:
            f.write(previous)
        raise ValueError('نسخه جدید تست نشد؛ برنامه به نسخه قبلی برگشت:\n' + detail[-4000:])
    try:
        cursor.execute("INSERT INTO ai_code_suggestions (title, suggestion, status, created_at, reviewed_at, owner_note) VALUES (?, ?, 'applied', ?, ?, ?)", (
            f'خوداصلاحی کد: {function_name}',
            f'موضوع: {topic}\nدلیل: {selection.get("reason", "")}\n\nنسخه جدید تابع:\n{new_function}',
            datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            f'پشتیبان: {backup_path}'
        ))
        conn.commit()
    except Exception:
        pass
    return {'function': function_name, 'reason': selection.get('reason', ''), 'backup': backup_path, 'message': 'نسخه جدید تولید، تست و با موفقیت اعمال شد.'}

# =========================================================
# پیشنهاد ارتقای کد — فقط با تأیید مالک
# =========================================================

def request_code_suggestion(topic=""):
    """از AI یک پیشنهاد بهبود برای برنامه می‌گیرد و آن را برای بررسی مالک ذخیره می‌کند.
    هیچ کدی به‌صورت خودکار در برنامه اعمال یا اجرا نمی‌شود."""

    focus = topic.strip() if topic and topic.strip() else "بهبود کلی عملکرد و تجربه کاربری برنامه"
    recent_learning = get_recent_ai_learning(10)

    prompt = (
        "تو دستیار فنی این برنامه فروشگاهی/حسابداری هستی (پایتون + Tkinter + SQLite + Ollama).\n"
        f"موضوع درخواستی برای بهبود: {focus}\n\n"
        f"یادگیری‌ها و مشاهدات اخیر:\n{recent_learning or 'موردی ثبت نشده'}\n\n"
        "یک پیشنهاد مشخص، کوچک، عملی و ایمن برای بهتر شدن برنامه بده.\n"
        "اگر نیاز به تغییر کد داری، نمونه کد کوتاه و تمیز بنویس.\n"
        "خروجی را دقیقاً با این ساختار بنویس:\n\n"
        "عنوان: <یک خط کوتاه>\n"
        "مشکل یا فرصت: <توضیح کوتاه>\n"
        "راه‌حل پیشنهادی: <توضیح واضح>\n"
        "نمونه کد (در صورت نیاز):\n"
        "```python\n"
        "# کد پیشنهادی اینجا\n"
        "```\n\n"
        "این پیشنهاد فقط برای بررسی مالک سیستم است و هیچ کدی به‌صورت خودکار اجرا نمی‌شود."
    )

    answer = _call_local_ai(prompt, num_predict=200, timeout=240)

    first_line = answer.strip().split("\n")[0]
    title = first_line.replace("عنوان:", "").strip()[:150] or focus

    cursor.execute("""
        INSERT INTO ai_code_suggestions (title, suggestion, status, created_at)
        VALUES (?, ?, 'pending', ?)
    """, (title, answer.strip(), datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
    conn.commit()

    return answer


def get_code_suggestions(status=None, limit=50):
    if status:
        cursor.execute("""
            SELECT id, title, suggestion, status, created_at, reviewed_at
            FROM ai_code_suggestions WHERE status=? ORDER BY id DESC LIMIT ?
        """, (status, int(limit)))
    else:
        cursor.execute("""
            SELECT id, title, suggestion, status, created_at, reviewed_at
            FROM ai_code_suggestions ORDER BY id DESC LIMIT ?
        """, (int(limit),))
    return cursor.fetchall()


def review_code_suggestion(suggestion_id, approve, note=""):
    status = "approved" if approve else "rejected"
    cursor.execute("""
        UPDATE ai_code_suggestions
        SET status=?, reviewed_at=?, owner_note=?
        WHERE id=?
    """, (status, datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str(note)[:1000], int(suggestion_id)))
    conn.commit()


def analyze_recent_emails_for_manager():
    cfg = _load_email_config()
    email_address = cfg.get("email", "").strip()
    if not email_address:
        raise ValueError("ابتدا حساب ایمیل را در «ایمیل هوشمند» تنظیم کنید.")
    password = _get_email_password(email_address)
    if not password:
        raise ValueError("رمز/رمز برنامه ایمیل در برنامه ذخیره نشده است. ابتدا اتصال ایمیل را آزمایش کنید.")

    result = _imap_fetch_latest(cfg, password, 8)
    if not result:
        return "ایمیل جدیدی برای تحلیل پیدا نشد."

    blocks = []
    for item in result:
        blocks.append(
            f"فرستنده: {item['from']}\nموضوع: {item['subject']}\nمتن: {item['body'][:5000]}"
        )

    prompt = (
        "ایمیل‌های اخیر را برای مدیر فروشگاه تحلیل کن. فقط بر اساس متن واقعی نظر بده. "
        "برای هر ایمیل مشخص کن: اهمیت (کم/متوسط/زیاد)، آیا نیاز به اقدام دارد، اقدام پیشنهادی، "
        "و آیا نشانه‌ای از مشکل مالی، سفارش، مشتری، تامین‌کننده یا کارمند وجود دارد. "
        "در پایان فقط مهم‌ترین موارد را در چند خط جمع‌بندی کن.\n\n" +
        "\n\n===== ایمیل =====\n\n".join(blocks)
    )
    answer = _call_local_ai(prompt, num_predict=200, timeout=240)

    for item in result:
        # برای هر ایمیل یک خلاصه مستقل کوتاه ذخیره می‌کنیم
        mini_prompt = (
            "این ایمیل را در حداکثر 500 کاراکتر برای حافظه مدیریتی خلاصه کن و اهمیت را تعیین کن.\n"
            f"فرستنده: {item['from']}\nموضوع: {item['subject']}\nمتن: {item['body'][:4000]}"
        )
        try:
            insight = _call_local_ai(mini_prompt, num_predict=120, timeout=120)
        except Exception:
            insight = answer[:500]
        importance = "high" if any(x in insight for x in ["زیاد", "مهم", "فوری"]) else "medium"
        save_email_insight(email_address, item["from"], item["subject"], insight, importance)

    remember_ai_learning("ایمیل", answer, source="email_manager", confidence=0.8)
    auto_created = auto_create_tasks_from_email_insights()
    return answer + f"\n\n📋 تعداد وظایف جدید ایجادشده از ایمیل: {auto_created}"


def remember_ai_learning(topic, lesson, source="manager", confidence=1.0):
    if not lesson or not str(lesson).strip():
        return
    cursor.execute("""
        INSERT INTO ai_learning (topic, lesson, source, confidence, created_at)
        VALUES (?, ?, ?, ?, ?)
    """, (
        str(topic).strip(),
        str(lesson).strip()[:1200],
        str(source).strip(),
        float(confidence),
        datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    ))
    conn.commit()


def get_recent_ai_learning(limit=8):
    cursor.execute("""
        SELECT topic, lesson, source, confidence, created_at
        FROM ai_learning
        ORDER BY id DESC
        LIMIT ?
    """, (int(limit),))
    rows = cursor.fetchall()
    if not rows:
        return ""
    parts = []
    for topic, lesson, source, confidence, created_at in rows:
        parts.append(f"موضوع: {topic} | درس: {lesson} | منبع: {source}")
    return "\n".join(parts)


def save_manager_history(report_date, summary, advice):
    cursor.execute("""
        INSERT INTO ai_manager_history (report_date, summary, ai_advice, created_at)
        VALUES (?, ?, ?, ?)
    """, (
        report_date,
        str(summary)[:3000],
        str(advice)[:5000],
        datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    ))
    conn.commit()


def get_manager_history(limit=5):
    cursor.execute("""
        SELECT report_date, summary, ai_advice
        FROM ai_manager_history
        ORDER BY id DESC
        LIMIT ?
    """, (int(limit),))
    rows = cursor.fetchall()
    if not rows:
        return ""
    parts = []
    for report_date, summary, advice in rows:
        parts.append(f"تاریخ: {report_date}\nخلاصه: {summary}\nپیشنهاد قبلی: {advice or '-'}")
    return "\n\n---\n\n".join(parts)


def record_employee_issue(employee, issue_type, description, severity="medium"):
    try:
        cursor.execute("""
            INSERT INTO employee_issues
            (employee, issue_type, description, severity, resolved, created_at)
            VALUES (?, ?, ?, ?, 0, ?)
        """, (
            employee,
            issue_type,
            description,
            severity,
            datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ))
        conn.commit()
    except Exception:
        pass


def get_employee_performance():
    """محاسبه عملکرد کارکنان بر اساس فعالیت‌ها، هشدارها و شاخص‌های واقعی."""
    today = datetime.now().strftime("%Y-%m-%d")
    # نقش‌های تحت نظارت مدیر هوش مصنوعی
    employees = ["کارمند انبار", "کارمند فروشگاه", "کارمند حسابداری", "کارمند کارپرداز"]
    result = []

    for employee in employees:
        # فعالیت‌های امروز (با نام نقش و نام واقعی)
        name_variants = [employee]
        if employee == "کارمند انبار":
            name_variants += ["علی", "انباردار"]
        elif employee == "کارمند فروشگاه":
            name_variants += ["موسی", "فروشنده"]
        elif employee == "کارمند حسابداری":
            name_variants += ["احمد", "حسابدار"]
        elif employee == "کارمند کارپرداز":
            name_variants += ["امید", "کارپرداز"]

        activities = 0
        for name in name_variants:
            cursor.execute("""
                SELECT COUNT(*) FROM employee_activity
                WHERE employee = ? AND activity_date LIKE ?
            """, (name, today + "%"))
            activities += int(cursor.fetchone()[0] or 0)

        cursor.execute("""
            SELECT COUNT(*) FROM employee_issues
            WHERE employee = ? AND resolved = 0
        """, (employee,))
        open_issues = int(cursor.fetchone()[0] or 0)

        # وظایف باز و انجام‌شده
        cursor.execute("""
            SELECT COUNT(*) FROM manager_tasks
            WHERE assigned_employee = ? AND status != 'done'
        """, (employee,))
        open_tasks = int(cursor.fetchone()[0] or 0)

        cursor.execute("""
            SELECT COUNT(*) FROM manager_tasks
            WHERE assigned_employee = ? AND status = 'done' AND completed_at LIKE ?
        """, (employee, today + "%"))
        done_today = int(cursor.fetchone()[0] or 0)

        # کار روزانه ثبت‌شده امروز
        daily_qty = 0
        for name in name_variants:
            cursor.execute("""
                SELECT COALESCE(SUM(quantity),0) FROM employee_daily_logs
                WHERE employee = ? AND work_date = ?
            """, (name, today))
            daily_qty += float(cursor.fetchone()[0] or 0)

        # کار واقعی سیستم (فروش/خرید/سند)
        real_actions = 0
        if employee == "کارمند فروشگاه":
            cursor.execute("SELECT COUNT(*) FROM sales WHERE substr(sale_date,1,10)=?", (today,))
            real_actions = int(cursor.fetchone()[0] or 0)
        elif employee == "کارمند کارپرداز":
            cursor.execute("SELECT COUNT(*) FROM purchases WHERE substr(purchase_date,1,10)=?", (today,))
            real_actions = int(cursor.fetchone()[0] or 0)
        elif employee == "کارمند حسابداری":
            cursor.execute("SELECT COUNT(*) FROM accounting WHERE substr(entry_date,1,10)=?", (today,))
            real_actions = int(cursor.fetchone()[0] or 0)
        elif employee == "کارمند انبار":
            for name in name_variants:
                cursor.execute("""
                    SELECT COUNT(*) FROM employee_activity
                    WHERE employee=? AND activity_date LIKE ? AND action LIKE '%کالا%'
                """, (name, today + "%"))
                real_actions += int(cursor.fetchone()[0] or 0)

        # امتیاز: پایه ۱۰۰
        score = 100
        score -= open_issues * 12
        score -= open_tasks * 5
        score += min(activities * 3, 12)
        score += min(done_today * 5, 15)
        score += min(int(daily_qty) * 2, 10)   # ثبت کار روزانه
        score += min(real_actions * 2, 12)      # کار واقعی سیستم
        score = max(0, min(100, score))

        result.append({
            "employee": employee,
            "activities": activities,
            "open_issues": open_issues,
            "open_tasks": open_tasks,
            "done_today": done_today,
            "daily_logs": daily_qty,
            "real_actions": real_actions,
            "score": score
        })

    # ثبت مسائل سیستمی
    cursor.execute("SELECT COUNT(*), COALESCE(SUM(total),0) FROM sales WHERE sale_date LIKE ?", (today + "%",))
    sales_count, sales_total = cursor.fetchone()
    sales_total = float(sales_total or 0)

    cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='income' AND entry_date LIKE ?", (today + "%",))
    income_total = float(cursor.fetchone()[0] or 0)

    mismatch = abs(sales_total - income_total)
    if mismatch > 0.01:
        record_employee_issue("کارمند حسابداری", "اختلاف مالی", f"اختلاف فروش و درآمد امروز: {mismatch:,.0f}", "high")

    if sales_count > 0:
        cursor.execute("""
            SELECT COUNT(*) FROM sales
            WHERE sale_date LIKE ? AND (quantity IS NULL OR quantity <= 0 OR total IS NULL OR total < 0)
        """, (today + "%",))
        bad_sales = int(cursor.fetchone()[0] or 0)
        if bad_sales:
            record_employee_issue("کارمند فروشگاه", "فروش نامعتبر", f"{bad_sales} فروش مشکوک امروز", "high")

    cursor.execute("SELECT COUNT(*) FROM products WHERE quantity < 0")
    negative_stock = int(cursor.fetchone()[0] or 0)
    if negative_stock:
        record_employee_issue("کارمند انبار", "موجودی منفی", f"{negative_stock} کالا موجودی منفی دارد", "high")

    # به‌روزرسانی نهایی امتیازها بعد از ثبت مسائل جدید
    for item in result:
        cursor.execute("SELECT COUNT(*) FROM employee_issues WHERE employee=? AND resolved=0", (item["employee"],))
        item["open_issues"] = int(cursor.fetchone()[0] or 0)
        score = 100 - (item["open_issues"] * 12) - (item.get("open_tasks", 0) * 5)
        score += min(item["activities"] * 3, 12) + min(item.get("done_today", 0) * 5, 15)
        score += min(int(item.get("daily_logs", 0)) * 2, 10)
        score += min(int(item.get("real_actions", 0)) * 2, 12)
        item["score"] = max(0, min(100, score))

    return result


def get_repeated_employee_issues(limit=15):
    cursor.execute("""
        SELECT employee, issue_type, COUNT(*) AS cnt, MAX(created_at)
        FROM employee_issues
        WHERE resolved = 0
        GROUP BY employee, issue_type
        HAVING COUNT(*) >= 2
        ORDER BY cnt DESC, MAX(created_at) DESC
        LIMIT ?
    """, (int(limit),))
    return cursor.fetchall()


def save_employee_review(employee, score, summary, ai_comment=""):
    try:
        cursor.execute("""
            INSERT INTO employee_reviews
            (employee, review_date, score, summary, ai_comment)
            VALUES (?, ?, ?, ?, ?)
        """, (
            employee,
            datetime.now().strftime("%Y-%m-%d"),
            float(score),
            str(summary)[:1000],
            str(ai_comment)[:3000]
        ))
        conn.commit()
    except Exception:
        pass


def get_employee_history(employee, limit=5):
    cursor.execute("""
        SELECT review_date, score, summary
        FROM employee_reviews
        WHERE employee = ?
        ORDER BY id DESC LIMIT ?
    """, (employee, int(limit)))
    rows = cursor.fetchall()
    if not rows:
        return "موردی ثبت نشده"
    return "\n".join(
        f"{d} | امتیاز {score:.0f} | {summary or '-'}"
        for d, score, summary in rows
    )


def save_learning_progress(employee, score, open_issues, completed_tasks, note=""):
    try:
        cursor.execute("""
            INSERT INTO employee_learning_progress
            (employee, review_date, score, open_issues, completed_tasks, note, created_at)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        """, (
            employee,
            datetime.now().strftime("%Y-%m-%d"),
            float(score),
            int(open_issues),
            int(completed_tasks),
            str(note)[:1500],
            datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ))
        conn.commit()
    except Exception:
        pass


def get_employee_learning_progress(employee, limit=8):
    cursor.execute("""
        SELECT review_date, score, open_issues, completed_tasks, note
        FROM employee_learning_progress
        WHERE employee = ?
        ORDER BY id DESC LIMIT ?
    """, (employee, int(limit)))
    rows = cursor.fetchall()
    if not rows:
        return "موردی ثبت نشده"
    return "\n".join(
        f"{d} | امتیاز {score:.0f} | هشدار {issues} | وظیفه تکمیل‌شده {tasks} | {note or '-'}"
        for d, score, issues, tasks, note in rows
    )


def save_training_plan(employee, skill, current_level, training_goal, actions, success_metric):
    cursor.execute("""
        INSERT INTO employee_training
        (employee, skill, current_level, training_goal, actions, success_metric, status, created_at)
        VALUES (?, ?, ?, ?, ?, ?, 'open', ?)
    """, (
        employee, str(skill)[:250], str(current_level)[:50],
        str(training_goal)[:1000], str(actions)[:2500],
        str(success_metric)[:1000],
        datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    ))
    conn.commit()


def get_open_training_plans(employee=None, limit=10):
    if employee:
        cursor.execute("""
            SELECT employee, skill, current_level, training_goal, actions, success_metric, status, created_at
            FROM employee_training
            WHERE employee = ? AND status = 'open'
            ORDER BY id DESC LIMIT ?
        """, (employee, int(limit)))
    else:
        cursor.execute("""
            SELECT employee, skill, current_level, training_goal, actions, success_metric, status, created_at
            FROM employee_training
            WHERE status = 'open'
            ORDER BY id DESC LIMIT ?
        """, (int(limit),))
    return cursor.fetchall()


def generate_employee_training_plan(employee):
    performance = get_employee_performance()
    item = next((x for x in performance if x["employee"] == employee), None)
    if not item:
        raise ValueError("کارمند پیدا نشد")

    repeated = [r for r in get_repeated_employee_issues(30) if r[0] == employee]
    repeated_text = "\n".join(f"{r[1]} | {r[2]} بار" for r in repeated) or "مورد تکراری ثبت نشده"
    history = get_employee_history(employee, 6)
    progress = get_employee_learning_progress(employee, 6)
    tasks = get_open_manager_tasks(employee=employee, limit=10)
    task_text = "\n".join(f"{t[1]} | {t[5]} | {t[6]}" for t in tasks) or "وظیفه بازی ثبت نشده"

    prompt = (
        "برای این کارمند یک برنامه آموزشی عملی و قابل اندازه‌گیری بساز. "
        "فقط بر اساس داده‌های واقعی زیر نتیجه‌گیری کن. سه بخش بده: مهارت اصلی، "
        "هدف آموزشی، 3 اقدام روزانه، و یک معیار موفقیت که بتوان با داده‌های برنامه سنجید.\n\n"
        f"کارمند: {employee}\n"
        f"امتیاز فعلی: {item['score']:.0f}/100\n"
        f"هشدارهای باز: {item['open_issues']}\n"
        f"خطاهای تکراری:\n{repeated_text}\n\n"
        f"سوابق ارزیابی:\n{history}\n\n"
        f"روند پیشرفت:\n{progress}\n\n"
        f"وظایف باز:\n{task_text}"
    )
    answer = _call_local_ai(prompt, num_predict=200, timeout=180)
    # ذخیره یک برنامه قابل پیگیری؛ حتی اگر خروجی مدل ساختار دقیق نداشته باشد.
    skill = repeated[0][1] if repeated else "بهبود عملکرد روزانه"
    goal = answer[:700]
    actions = answer[:2200]
    metric = f"رسیدن به امتیاز بالاتر از {min(100, max(70, item['score'] + 10)):.0f} و کاهش هشدارهای باز"
    save_training_plan(employee, skill, "needs_improvement" if item["score"] < 80 else "developing", goal, actions, metric)
    remember_ai_learning(f"آموزش {employee}", answer, source="employee_training", confidence=0.9)
    return answer


def evaluate_learning_progress():
    performance = get_employee_performance()
    results=[]
    for item in performance:
        emp=item["employee"]
        cursor.execute("SELECT COUNT(*) FROM manager_tasks WHERE assigned_employee=? AND status='done' AND completed_at LIKE ?", (emp, datetime.now().strftime('%Y-%m-%d')+"%"))
        completed=int(cursor.fetchone()[0] or 0)
        save_learning_progress(emp, item["score"], item["open_issues"], completed, "ارزیابی خودکار مدیر")
        cursor.execute("SELECT score FROM employee_learning_progress WHERE employee=? ORDER BY id DESC LIMIT 2", (emp,))
        rows=cursor.fetchall()
        change=None
        if len(rows)==2:
            change=float(rows[0][0])-float(rows[1][0])
        results.append((emp, item["score"], change))
    return results


def build_manager_report():
    today = datetime.now().strftime("%Y-%m-%d")

    cursor.execute("SELECT COUNT(*), COALESCE(SUM(quantity),0) FROM products")
    product_count, total_quantity = cursor.fetchone()

    cursor.execute("""
        SELECT COUNT(*)
        FROM products
        WHERE quantity <= 5
    """)
    low_stock_count = cursor.fetchone()[0]

    cursor.execute("""
        SELECT COALESCE(SUM(quantity * COALESCE(avg_buy_price,buy_price,0)),0)
        FROM products
    """)
    stock_value = float(cursor.fetchone()[0] or 0)

    cursor.execute("""
        SELECT COUNT(*), COALESCE(SUM(total),0)
        FROM sales
        WHERE sale_date LIKE ?
    """, (today + "%",))
    sales_count, sales_total = cursor.fetchone()
    sales_total = float(sales_total or 0)

    cursor.execute("""
        SELECT COUNT(*), COALESCE(SUM(amount),0)
        FROM accounting
        WHERE entry_type = 'income'
          AND entry_date LIKE ?
    """, (today + "%",))
    income_count, income_total = cursor.fetchone()
    income_total = float(income_total or 0)

    cursor.execute("""
        SELECT COUNT(*), COALESCE(SUM(amount),0)
        FROM accounting
        WHERE entry_type = 'expense'
          AND entry_date LIKE ?
    """, (today + "%",))
    expense_count, expense_total = cursor.fetchone()
    expense_total = float(expense_total or 0)

    cursor.execute("SELECT COUNT(*) FROM customers")
    customer_count = cursor.fetchone()[0]

    cursor.execute("""
        SELECT name, quantity, unit
        FROM products
        WHERE quantity <= 5
        ORDER BY quantity ASC, name
        LIMIT 10
    """)
    low_rows = cursor.fetchall()

    cursor.execute("""
        SELECT name, quantity, total, sale_date
        FROM sales
        ORDER BY id DESC
        LIMIT 10
    """)
    last_sales = cursor.fetchall()

    report = [
        "گزارش مدیریتی امروز: " + today,
        "",
        "کارمند انبار:",
        f"تعداد کالاها: {product_count}",
        f"مجموع موجودی: {total_quantity}",
        f"ارزش تقریبی خرید موجودی: {stock_value:,.0f}",
        f"کالاهای کم‌موجودی (<=5): {low_stock_count}",
        "",
        "کارمند فروشگاه:",
        f"تعداد فروش امروز: {sales_count}",
        f"مبلغ فروش امروز: {sales_total:,.0f}",
        "",
        "کارمند حسابداری:",
        f"درآمد ثبت‌شده امروز: {income_total:,.0f}",
        f"هزینه ثبت‌شده امروز: {expense_total:,.0f}",
        f"سود خالص امروز: {(income_total-expense_total):,.0f}",
        "",
        f"تعداد مشتریان: {customer_count}",
    ]

    if low_rows:
        report += ["", "کالاهای کم‌موجودی:"]
        for name, quantity, unit in low_rows:
            report.append(f"- {name}: {quantity} {unit}")

    report += ["", "آخرین فروش‌ها:"]
    for name, quantity, total, sale_date in last_sales:
        report.append(f"- {name} | تعداد {quantity} | مبلغ {float(total):,.0f} | {sale_date}")

    mismatch = abs(sales_total - income_total)
    performance = get_employee_performance()
    report += ["", "امتیاز عملکرد کارکنان:"]
    for item in performance:
        report.append(
            f"- {item['employee']}: امتیاز {item['score']:.0f}/100 | "
            f"فعالیت امروز {item['activities']} | هشدار باز {item['open_issues']}"
        )

    repeated = get_repeated_employee_issues()
    if repeated:
        report += ["", "خطاهای تکراری:"]
        for employee, issue_type, cnt, last_seen in repeated:
            report.append(f"- {employee}: {issue_type} | تکرار {cnt} بار")

    report += ["", f"اختلاف فروش فروشگاه با درآمد حسابداری امروز: {mismatch:,.0f}"]
    email_insights = get_recent_email_insights(5)
    report += ["", "تحلیل‌های اخیر ایمیل:", email_insights]
    report += ["", "وظایف باز کارکنان:", get_task_summary()]
    run_smart_monitoring()
    report += ["", "🚨 هشدارهای باز مدیر:", get_alert_summary(10)]
    return "\n".join(report), {
        "sales_total": sales_total,
        "income_total": income_total,
        "expense_total": expense_total,
        "low_stock_count": low_stock_count,
        "mismatch": mismatch,
    }


def open_task_center_window(parent=None):
    host = parent if parent is not None else window
    task_window = tk.Toplevel(host)
    task_window.title("📋 مرکز وظایف مدیر")
    task_window.geometry("1200x780")

    tk.Label(task_window, text="📋 مرکز کامل وظایف کارکنان",
             font=("Tahoma", 18, "bold")).pack(pady=10)

    top = tk.Frame(task_window)
    top.pack(fill=tk.X, padx=10, pady=5)

    tk.Label(top, text="عنوان:").grid(row=0, column=0, padx=5)
    title_entry = tk.Entry(top, width=30)
    title_entry.grid(row=0, column=1, padx=5)

    tk.Label(top, text="کارمند:").grid(row=0, column=2, padx=5)
    employee_var = tk.StringVar(value="همه کارکنان")
    employee_box = ttk.Combobox(
        top, textvariable=employee_var, state="readonly", width=20,
        values=["همه کارکنان", "کارمند انبار", "کارمند فروشگاه",
                "کارمند حسابداری", "کارمند کارپرداز"])
    employee_box.grid(row=0, column=3, padx=5)

    tk.Label(top, text="وضعیت:").grid(row=0, column=4, padx=5)
    status_var = tk.StringVar(value="all")
    status_box = ttk.Combobox(
        top, textvariable=status_var, state="readonly", width=16,
        values=["all", "open", "in_progress", "waiting_approval", "failed", "done"])
    status_box.grid(row=0, column=5, padx=5)

    tk.Label(top, text="اولویت:").grid(row=1, column=0, padx=5)
    priority_var = tk.StringVar(value="medium")
    priority_box = ttk.Combobox(
        top, textvariable=priority_var, state="readonly", width=10,
        values=["high", "medium", "low"])
    priority_box.grid(row=1, column=1, padx=5)

    tk.Label(top, text="توضیح:").grid(row=1, column=2, padx=5)
    desc_entry = tk.Entry(top, width=55)
    desc_entry.grid(row=1, column=3, columnspan=3, padx=5, pady=7)

    summary_label = tk.Label(task_window, text="", font=("Tahoma", 10, "bold"), anchor="w")
    summary_label.pack(fill=tk.X, padx=12, pady=3)

    cols = ("id", "title", "employee", "priority", "status", "source", "date")
    tree = ttk.Treeview(task_window, columns=cols, show="headings", height=18)
    headers = {"id":"شناسه", "title":"عنوان", "employee":"کارمند",
               "priority":"اولویت", "status":"وضعیت", "source":"منبع", "date":"تاریخ"}
    widths = {"id":60, "title":260, "employee":150, "priority":80,
              "status":130, "source":120, "date":150}
    for c in cols:
        tree.heading(c, text=headers[c])
        tree.column(c, width=widths[c])
    tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=8)

    detail = scrolledtext.ScrolledText(task_window, wrap=tk.WORD, height=9)
    detail.pack(fill=tk.X, padx=10, pady=5)

    def show_detail(event=None):
        detail.delete("1.0", tk.END)
        selected = tree.selection()
        if not selected:
            return
        row = _task_row(int(selected[0]))
        if not row:
            return
        (_id, title, desc, emp, source, priority, status, due, created,
         completed, note, started, result, mode, error) = row
        detail.insert(tk.END,
            f"شناسه: {_id}\nکارمند: {emp}\nوضعیت: {status}\n"
            f"اولویت: {priority}\nمنبع: {source}\nایجاد: {created}\n"
            f"شروع اجرا: {started or '-'}\nاتمام: {completed or '-'}\n\n"
            f"شرح:\n{desc or '-'}\n\nنتیجه اجرا:\n{result or '-'}\n"
            f"\nخطا:\n{error or '-'}\nیادداشت مدیر:\n{note or '-'}")

    tree.bind("<<TreeviewSelect>>", show_detail)

    def refresh(run_monitor=True):
        if run_monitor:
            try:
                seed_default_employee_tasks()
                run_smart_monitoring()
            except Exception as exc:
                print("Task center monitoring error:", exc)

        for item in tree.get_children():
            tree.delete(item)

        rows = get_all_manager_tasks(
            employee=employee_var.get(),
            status_filter=status_var.get(),
            limit=500)
        for row in rows:
            task_id, title, desc, emp, source, priority, status, due, created = row[:9]
            tree.insert("", tk.END, iid=str(task_id),
                        values=(task_id, title, emp, priority, status, source, due or created))

        counts = get_manager_task_counts(employee_var.get())
        summary_label.config(
            text=(f"همه: {counts['total']} | باز: {counts['open']} | "
                  f"در حال اجرا: {counts['in_progress']} | نیازمند تأیید: "
                  f"{counts['waiting_approval']} | خطادار: {counts['failed']} | "
                  f"انجام‌شده: {counts['done']}"))
        show_detail()

    def add_task():
        title = title_entry.get().strip()
        desc = desc_entry.get().strip()
        emp = employee_var.get()
        if not title:
            messagebox.showwarning("وظیفه", "عنوان وظیفه را وارد کنید.", parent=task_window)
            return
        if emp == "همه کارکنان":
            messagebox.showwarning("وظیفه", "یک کارمند مشخص انتخاب کنید.", parent=task_window)
            return
        create_manager_task(title, desc, emp, source="manual", priority=priority_var.get())
        title_entry.delete(0, tk.END)
        desc_entry.delete(0, tk.END)
        refresh(False)

    def execute_selected():
        selected = tree.selection()
        if not selected:
            messagebox.showwarning("وظیفه", "یک وظیفه را انتخاب کنید.", parent=task_window)
            return
        row = _task_row(int(selected[0]))
        if not row:
            return
        if row[6] == "done":
            messagebox.showinfo("وظیفه", "این وظیفه قبلاً انجام شده است.", parent=task_window)
            return
        try:
            result = execute_employee_task(int(row[0]), str(row[3]))
            messagebox.showinfo("اجرای وظیفه", result[:5000], parent=task_window)
        except Exception as e:
            messagebox.showerror("خطای اجرای وظیفه", str(e), parent=task_window)
        refresh(False)

    def complete_selected():
        selected = tree.selection()
        if not selected:
            messagebox.showwarning("وظیفه", "یک وظیفه را انتخاب کنید.", parent=task_window)
            return
        update_manager_task_status(int(selected[0]), "done",
                                   result="به صورت دستی توسط مدیر انجام شد.")
        refresh(False)

    def email_tasks():
        count = auto_create_tasks_from_email_insights()
        refresh(False)
        messagebox.showinfo("ایمیل", f"{count} وظیفه جدید از ایمیل‌ها ایجاد شد.", parent=task_window)

    def force_monitor():
        try:
            count = run_smart_monitoring()
            seed_default_employee_tasks()
            refresh(False)
            messagebox.showinfo("نظارت خودکار",
                                f"نظارت انجام شد. {count} مورد بررسی شد.",
                                parent=task_window)
        except Exception as e:
            messagebox.showerror("نظارت خودکار", str(e), parent=task_window)

    btns = tk.Frame(task_window)
    btns.pack(pady=5)
    tk.Button(btns, text="➕ ایجاد وظیفه", command=add_task).pack(side=tk.LEFT, padx=5)
    tk.Button(btns, text="🤖 اجرای وظیفه توسط کارمند",
              command=execute_selected).pack(side=tk.LEFT, padx=5)
    tk.Button(btns, text="✅ انجام شد دستی",
              command=complete_selected).pack(side=tk.LEFT, padx=5)
    tk.Button(btns, text="📧 ساخت وظایف از ایمیل",
              command=email_tasks).pack(side=tk.LEFT, padx=5)
    tk.Button(btns, text="🧠 بررسی خودکار الآن",
              command=force_monitor).pack(side=tk.LEFT, padx=5)
    tk.Button(btns, text="🔄 بروزرسانی",
              command=lambda: refresh(True)).pack(side=tk.LEFT, padx=5)

    employee_box.bind("<<ComboboxSelected>>", lambda e: refresh(False))
    status_box.bind("<<ComboboxSelected>>", lambda e: refresh(False))

    refresh(True)

def open_manager_window():
    manager_window = tk.Toplevel(window)
    manager_window.title("👔 مدیر هوش مصنوعی")
    manager_window.geometry("1000x720")

    title = tk.Label(
        manager_window,
        text="👔 مدیر هوش مصنوعی — نظارت بر کارکنان",
        font=("Tahoma", 18, "bold")
    )
    title.pack(pady=10)

    info = tk.Label(
        manager_window,
        text="هوش مصنوعی گزارش انبار، فروشگاه و حسابداری را بررسی می‌کند.",
        font=("Tahoma", 11)
    )
    info.pack(pady=5)

    report_text = scrolledtext.ScrolledText(
        manager_window,
        wrap=tk.WORD,
        font=("Tahoma", 11),
        height=28
    )
    report_text.pack(fill=tk.BOTH, expand=True, padx=12, pady=10)

    def refresh_report():
        report, stats = build_manager_report()
        report_text.config(state=tk.NORMAL)
        report_text.delete("1.0", tk.END)
        report_text.insert(tk.END, report)

        warnings = []
        if stats["mismatch"] > 0.01:
            warnings.append("⚠️ بین فروش فروشگاه و درآمد حسابداری اختلاف وجود دارد.")
        if stats["low_stock_count"] > 0:
            warnings.append("⚠️ تعدادی کالا کم‌موجودی هستند.")
        if stats["expense_total"] > stats["income_total"]:
            warnings.append("⚠️ هزینه امروز از درآمد امروز بیشتر است.")

        if warnings:
            report_text.insert(tk.END, "\n\n================ هشدار مدیر ================\n")
            for warning in warnings:
                report_text.insert(tk.END, warning + "\n")

        report_text.config(state=tk.DISABLED)

    def ai_check():
        report, _ = build_manager_report()
        report_text.config(state=tk.NORMAL)
        report_text.insert(tk.END, "\n\n⏳ هوش مصنوعی در حال بررسی عملکرد کارکنان...\n")
        report_text.config(state=tk.DISABLED)
        manager_window.update_idletasks()

        try:
            profile = get_ai_profile()
            recent_learning = get_recent_ai_learning(2)
            recent_history = get_manager_history(3)
            performance = get_employee_performance()
            performance_text = "\n".join(
                f"{x['employee']}: امتیاز {x['score']:.0f}/100 | فعالیت {x['activities']} | هشدار باز {x['open_issues']}"
                for x in performance
            )
            repeated = get_repeated_employee_issues()
            repeated_text = "\n".join(
                f"{e} | {t} | {c} بار" for e, t, c, _ in repeated
            ) or "موردی ثبت نشده"

            prompt = (
                f"تو {profile['role']} سیستم هستی. {profile['owner_name']} مالک و خالق سیستم است. "
                f"مأموریت تو: {profile['mission']}\n"
                f"قوانین: {profile['rules']}\n\n"
                "گزارش فعلی را بررسی کن. مشکلات، اختلاف‌ها، کمبودهای مهم، تغییرات قابل توجه "
                "و سه اقدام پیشنهادی بعدی را مشخص کن. چیزی را که در داده‌ها نیست حدس نزن. "
                "از سوابق قبلی برای یافتن روندها استفاده کن، ولی آن‌ها را با وضعیت فعلی اشتباه نگیر. "
                "پاسخ فارسی، عملی و کوتاه باشد.\n\n"
                "یادگیری‌های اخیر:\n" + (recent_learning or "موردی ثبت نشده") + "\n\n"
                "گزارش‌های مدیریتی اخیر:\n" + (recent_history or "موردی ثبت نشده") + "\n\n"
                "امتیاز کارکنان:\n" + (performance_text or "موردی ثبت نشده") + "\n\n"
                "خطاهای تکراری:\n" + repeated_text + "\n\n"
                "تحلیل‌های اخیر ایمیل:\n" + get_recent_email_insights(5) + "\n\n"
                "وظایف باز کارکنان:\n" + get_task_summary() + "\n\n"
                "برنامه‌های آموزشی باز:\n" + "\n".join(
                    f"{r[0]} | مهارت: {r[1]} | هدف: {r[3]} | معیار: {r[5]}"
                    for r in get_open_training_plans(limit=8)
                ) + "\n\n"
                "روند یادگیری فعلی:\n" + "\n".join(
                    f"{emp}: امتیاز {score:.0f}" + (f" | تغییر اخیر {change:+.0f}" if change is not None else "")
                    for emp, score, change in evaluate_learning_progress()
                ) + "\n\n"
                "برای هر کارمند فقط بر اساس داده‌های واقعی برنامه نظر بده و موارد مشکوک را از موارد قطعی جدا کن. "
                "اگر برنامه آموزشی باز وجود دارد، بررسی کن که نتیجه آن دیده می‌شود یا نه. "
                "در صورت افت عملکرد، برنامه آموزشی را تشدید یا بازطراحی کن.\n\n"
                "گزارش فعلی:\n" + report
            )

            response = requests.post(
                "http://localhost:11434/api/chat",
                json={
                    "model": get_ai_model(),
                    "messages": [
                        {"role": "system", "content": "تو مدیر و ناظر داخلی فروشگاه هستی."},
                        {"role": "user", "content": prompt}
                    ],
                    "stream": False,
                    "keep_alive": "2m",
                    "options": {"num_predict": 100, "temperature": 0.15, "num_ctx": 1024}
                },
                timeout=180
            )
            response.raise_for_status()
            answer = response.json()["message"]["content"]

            report_text.config(state=tk.NORMAL)
            report_text.insert(tk.END, "\n\n================ نظر مدیر هوش مصنوعی ================\n")
            report_text.insert(tk.END, answer + "\n")
            report_text.config(state=tk.DISABLED)
            report_text.see(tk.END)
            save_manager_history(datetime.now().strftime("%Y-%m-%d"), report, answer)
            for item in get_employee_performance():
                save_employee_review(
                    item["employee"],
                    item["score"],
                    f"فعالیت امروز: {item['activities']} | هشدار باز: {item['open_issues']}",
                    answer[:2000]
                )
            remember_ai_learning("مدیریت", answer, source="ai_manager", confidence=0.85)
            speak_text(answer)
            log_employee_activity("مدیر هوش مصنوعی", "بررسی عملکرد کارکنان", answer[:500])
        except Exception as e:
            report_text.config(state=tk.NORMAL)
            report_text.insert(tk.END, "\n❌ خطای بررسی هوش مصنوعی: " + str(e) + "\n")
            report_text.config(state=tk.DISABLED)

    buttons = tk.Frame(manager_window)
    buttons.pack(pady=8)

    tk.Button(
        buttons,
        text="🔄 بروزرسانی گزارش",
        font=("Tahoma", 11, "bold"),
        command=refresh_report
    ).pack(side=tk.LEFT, padx=5)

    tk.Button(
        buttons,
        text="🤖 بررسی توسط مدیر هوش مصنوعی",
        font=("Tahoma", 11, "bold"),
        command=ai_check
    ).pack(side=tk.LEFT, padx=5)

    def show_employee_learning():
        performance = get_employee_performance()
        history_window = tk.Toplevel(manager_window)
        history_window.title("🧠 یادگیری و ارزیابی کارکنان")
        history_window.geometry("900x650")
        text = scrolledtext.ScrolledText(history_window, wrap=tk.WORD, font=("Tahoma", 11))
        text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        lines = ["🧠 ارزیابی و یادگیری عملکرد کارکنان", ""]
        for item in performance:
            lines.append(f"{item['employee']} — امتیاز {item['score']:.0f}/100")
            lines.append(f"فعالیت امروز: {item['activities']} | هشدار باز: {item['open_issues']}")
            lines.append("سوابق اخیر:")
            lines.append(get_employee_history(item['employee']))
            lines.append("")
        repeated = get_repeated_employee_issues()
        lines.append("⚠️ خطاهای تکراری")
        if repeated:
            for e, t, c, last in repeated:
                lines.append(f"- {e}: {t} | {c} بار")
        else:
            lines.append("موردی ثبت نشده")

        lines.append("\n📚 برنامه‌های آموزشی باز")
        plans = get_open_training_plans(limit=10)
        if plans:
            for e, skill, level, goal, actions, metric, status, created in plans:
                lines.append(f"- {e} | {skill} | معیار: {metric}")
        else:
            lines.append("موردی ثبت نشده")

        lines.append("\n📈 روند پیشرفت")
        for e, score, change in evaluate_learning_progress():
            change_text = "بدون سابقه قبلی" if change is None else f"تغییر اخیر: {change:+.0f}"
            lines.append(f"- {e}: امتیاز {score:.0f}/100 | {change_text}")

        text.insert("1.0", "\n".join(lines))
        text.config(state=tk.DISABLED)

        training_buttons = tk.Frame(history_window)
        training_buttons.pack(pady=6)

        def make_training():
            emp = employee_choice.get()
            try:
                ans = generate_employee_training_plan(emp)
                text.config(state=tk.NORMAL)
                text.insert(tk.END, f"\n\n================ برنامه آموزشی {emp} ================\n{ans}\n")
                text.config(state=tk.DISABLED)
                text.see(tk.END)
                messagebox.showinfo("یادگیری کارکنان", "برنامه آموزشی ثبت شد.", parent=history_window)
            except Exception as e:
                messagebox.showerror("یادگیری", str(e), parent=history_window)

        employee_choice = tk.StringVar(value="کارمند فروشگاه")
        ttk.Combobox(
            training_buttons, textvariable=employee_choice, state="readonly", width=20,
            values=["کارمند انبار", "کارمند فروشگاه", "کارمند حسابداری", "کارمند کارپرداز"]
        ).pack(side=tk.LEFT, padx=5)
        tk.Button(
            training_buttons, text="🤖 ساخت برنامه آموزشی", font=("Tahoma", 10, "bold"),
            command=make_training
        ).pack(side=tk.LEFT, padx=5)

    tk.Button(
        buttons,
        text="🧠 یادگیری کارکنان",
        font=("Tahoma", 11, "bold"),
        command=show_employee_learning
    ).pack(side=tk.LEFT, padx=5)

    def analyze_emails():
        report_text.config(state=tk.NORMAL)
        report_text.insert(tk.END, "\n\n⏳ مدیر هوش مصنوعی در حال بررسی ایمیل‌های اخیر است...\n")
        report_text.config(state=tk.DISABLED)
        manager_window.update_idletasks()

        def worker():
            try:
                answer = analyze_recent_emails_for_manager()
                def show():
                    report_text.config(state=tk.NORMAL)
                    report_text.insert(
                        tk.END,
                        "\n================ تحلیل ایمیل‌های مدیر ================\n" + answer + "\n"
                    )
                    report_text.config(state=tk.DISABLED)
                    report_text.see(tk.END)
                    save_manager_history(
                        datetime.now().strftime("%Y-%m-%d"),
                        "تحلیل ایمیل‌های اخیر",
                        answer
                    )
                    speak_text(answer)
                manager_window.after(0, show)
            except Exception as e:
                manager_window.after(
                    0,
                    lambda: messagebox.showerror("خطای تحلیل ایمیل", str(e))
                )

        threading.Thread(target=worker, daemon=True).start()

    tk.Button(
        buttons,
        text="📧 بررسی ایمیل‌های مهم",
        font=("Tahoma", 11, "bold"),
        command=analyze_emails
    ).pack(side=tk.LEFT, padx=5)

    tk.Button(
        buttons,
        text="📋 مرکز وظایف",
        font=("Tahoma", 11, "bold"),
        command=lambda: open_task_center_window(manager_window)
    ).pack(side=tk.LEFT, padx=5)

    def show_alerts():
        run_smart_monitoring()
        aw = tk.Toplevel(manager_window)
        aw.title("🚨 هشدارهای مدیر")
        aw.geometry("900x600")
        text = scrolledtext.ScrolledText(aw, wrap=tk.WORD, font=("Tahoma", 11))
        text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        rows = get_open_manager_alerts(100)
        if not rows:
            text.insert("1.0", "✅ هشدار بازی وجود ندارد.")
        else:
            lines=["🚨 هشدارهای باز سیستم", ""]
            for alert_id, alert_type, severity, title, details, employee, created_at in rows:
                lines.append(f"#{alert_id} | شدت: {severity} | {title}")
                if employee: lines.append(f"کارمند مرتبط: {employee}")
                lines.append(f"زمان: {created_at}")
                lines.append(details or "")
                lines.append("------------------------------")
            text.insert("1.0", "\n".join(lines))
        text.config(state=tk.DISABLED)
        tk.Button(aw, text="بستن", command=aw.destroy).pack(pady=5)

    tk.Button(
        buttons, text="🚨 هشدارهای مدیر",
        font=("Tahoma", 11, "bold"), command=show_alerts
    ).pack(side=tk.LEFT, padx=5)

    refresh_report()

# =========================================================
# ارسال سؤال به هوش مصنوعی
# =========================================================


# =========================================================
# ابزار هوشمند انبار
# =========================================================

def normalize_product_name(text):

    return (
        str(text)
        .replace("‌", "")
        .replace(" ", "")
        .replace("-", "")
        .replace("_", "")
        .replace("ي", "ی")
        .replace("ى", "ی")
        .replace("ك", "ک")
        .lower()
        .strip()
    )


def find_product(product_name):

    target = normalize_product_name(product_name)

    if not target:
        return None

    cursor.execute("""
        SELECT id, code, name, quantity,
               buy_price, sell_price, unit
        FROM products
    """)

    rows = cursor.fetchall()

    for row in rows:

        name_normal = normalize_product_name(row[2])
        code_normal = normalize_product_name(row[1])

        if target == name_normal:
            return row

        if target in name_normal:
            return row

        if name_normal in target:
            return row

        if target == code_normal:
            return row

    return None


# =========================================================
# تغییر موجودی
# =========================================================

def change_stock(product_name, amount):

    try:

        product = find_product(product_name)

        if not product:
            return "❌ محصول پیدا نشد."

        product_id = product[0]
        real_name = product[2]
        old_quantity = float(product[3])
        unit = product[6]

        amount = float(amount)

        new_quantity = old_quantity + amount

        if new_quantity < 0:

            return (
                "❌ موجودی کافی نیست.\n"
                "کالا: " + str(real_name) + "\n"
                "موجودی فعلی: " + str(old_quantity) + " " + str(unit)
            )

        cursor.execute("""
            UPDATE products
            SET quantity = ?
            WHERE id = ?
        """, (
            new_quantity,
            product_id
        ))

        conn.commit()

        if amount >= 0:

            return (
                "✅ موجودی با موفقیت افزایش یافت.\n\n"
                "کالا: " + str(real_name) + "\n"
                "موجودی قبلی: " + str(old_quantity) + " " + str(unit) + "\n"
                "مقدار اضافه‌شده: " + str(amount) + " " + str(unit) + "\n"
                "موجودی جدید: " + str(new_quantity) + " " + str(unit)
            )

        else:

            return (
                "✅ موجودی با موفقیت کاهش یافت.\n\n"
                "کالا: " + str(real_name) + "\n"
                "موجودی قبلی: " + str(old_quantity) + " " + str(unit) + "\n"
                "مقدار کم‌شده: " + str(abs(amount)) + " " + str(unit) + "\n"
                "موجودی جدید: " + str(new_quantity) + " " + str(unit)
            )

    except Exception as e:

        return "❌ خطا در تغییر موجودی: " + str(e)


# =========================================================
# پیدا کردن کالا داخل سؤال
# =========================================================

def find_product_from_question(question):

    normalized_question = normalize_product_name(question)

    cursor.execute("""
        SELECT id, code, name, quantity,
               buy_price, sell_price, unit
        FROM products
    """)

    rows = cursor.fetchall()

    best_product = None
    best_length = 0

    for row in rows:

        name_normal = normalize_product_name(row[2])
        code_normal = normalize_product_name(row[1])

        if (
            name_normal
            and name_normal in normalized_question
            and len(name_normal) > best_length
        ):

            best_product = row
            best_length = len(name_normal)

        elif (
            code_normal
            and code_normal in normalized_question
            and len(code_normal) > best_length
        ):

            best_product = row
            best_length = len(code_normal)

    return best_product


# =========================================================
# پاسخ مستقیم موجودی و قیمت
# =========================================================

def direct_inventory_answer(question):

    product = find_product_from_question(question)

    if not product:
        return None

    text = normalize_product_name(question)

    stock_words = [
        "موجودی",
        "موجوده",
        "چندتا",
        "چندعدد",
        "تعداد"
    ]

    price_words = [
        "قیمت",
        "فروش",
        "خرید"
    ]

    is_stock = any(
        word in text
        for word in stock_words
    )

    is_price = any(
        word in text
        for word in price_words
    )

    if is_stock:

        name = product[2]
        quantity = product[3]
        unit = product[6]

        return (
            "📦 موجودی واقعی " +
            str(name) +
            ": " +
            str(quantity) +
            " " +
            str(unit)
        )

    if is_price:

        name = product[2]
        buy_price = product[4]
        sell_price = product[5]

        return (
            "💰 اطلاعات قیمت\n\n"
            "کالا: " + str(name) + "\n"
            "قیمت خرید: " + f"{float(buy_price):,.0f}" + "\n"
            "قیمت فروش: " + f"{float(sell_price):,.0f}"
        )

    return None


# =========================================================
# نمایش پاسخ مستقیم
# =========================================================

def show_direct_answer(question, answer):

    chat.insert(
        tk.END,
        "شما: " +
        question +
        "\n\n"
    )

    chat.insert(
        tk.END,
        "AI: " +
        answer +
        "\n\n"
    )

    chat.see(tk.END)

    conversation.append({
        "role": "user",
        "content": question
    })

    conversation.append({
        "role": "assistant",
        "content": answer
    })

    save_memory()

    try:
        speak_text(answer)
    except Exception:
        pass


# =========================================================
# ارسال سؤال به هوش مصنوعی
# =========================================================

def send_message():

    question = entry.get().strip()

    if not question:
        return

    # تبدیل اعداد فارسی و عربی
    command_text = question.translate(
        str.maketrans(
            "۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩",
            "01234567890123456789"
        )
    )

    entry.delete(
        0,
        tk.END
    )

    # =====================================================
    # تشخیص عدد
    # =====================================================

    number_match = re.search(
        r"\d+(?:\.\d+)?",
        command_text
    )

    # =====================================================
    # افزایش موجودی
    # مثال:
    # 10 تا لپ تاپ اضافه کن
    # لپتاپ 10 تا اضافه کن
    # =====================================================

    if (
        ("اضافه" in command_text)
        or
        ("افزایش" in command_text)
    ):

        if number_match:

            amount = float(
                number_match.group()
            )

            product = find_product_from_question(
                command_text
            )

            if product:

                result = change_stock(
                    product[2],
                    amount
                )

                show_direct_answer(
                    question,
                    result
                )

                return


    # =====================================================
    # کاهش موجودی
    # مثال:
    # 5 تا لپ تاپ کم کن
    # لپ تاپ 5 تا کم کن
    # =====================================================

    if (
        ("کم کن" in command_text)
        or
        ("کاهش" in command_text)
        or
        ("کم" in command_text and "موجودی" in command_text)
    ):

        if number_match:

            amount = float(
                number_match.group()
            )

            product = find_product_from_question(
                command_text
            )

            if product:

                result = change_stock(
                    product[2],
                    -amount
                )

                show_direct_answer(
                    question,
                    result
                )

                return


    # =====================================================
    # سؤال مستقیم موجودی یا قیمت
    # =====================================================

    direct_answer = direct_inventory_answer(
        command_text
    )

    if direct_answer:

        show_direct_answer(
            question,
            direct_answer
        )

        return



    # =====================================================
    # دستورهای سریع اجرایی (بدون انتظار مدل)
    # =====================================================

    qlow = command_text.strip()

    # گزارش فروش امروز
    if any(k in qlow for k in ("فروش امروز", "گزارش فروش", "چقدر فروختیم", "فروش روزانه")):
        today = datetime.now().strftime("%Y-%m-%d")
        cursor.execute("SELECT COUNT(*), COALESCE(SUM(total),0) FROM sales WHERE substr(sale_date,1,10)=?", (today,))
        cnt, total = cursor.fetchone()
        cursor.execute("SELECT name, quantity, total FROM sales WHERE substr(sale_date,1,10)=? ORDER BY id DESC LIMIT 8", (today,))
        rows = cursor.fetchall()
        lines = [f"فروش امروز: {int(cnt or 0)} فاکتور | جمع {float(total or 0):,.0f} ریال"]
        for name, qty, t in rows:
            lines.append(f"• {name}: {qty:g} — {float(t or 0):,.0f}")
        show_direct_answer(question, "\n".join(lines) if rows else lines[0] + "\nهنوز فروشی ثبت نشده.")
        return

    # کالاهای کم‌موجودی
    if any(k in qlow for k in ("کمبود موجودی", "موجودی کم", "کالای کم", "رو به اتمام")):
        cursor.execute("SELECT name, quantity, unit FROM products WHERE quantity <= 5 ORDER BY quantity LIMIT 15")
        rows = cursor.fetchall()
        if not rows:
            show_direct_answer(question, "کالای کم‌موجودی (≤۵) پیدا نشد.")
        else:
            lines = ["کالاهای کم‌موجودی:"] + [f"• {n}: {q:g} {u}" for n, q, u in rows]
            show_direct_answer(question, "\n".join(lines))
        return

    # موجودی منفی
    if "موجودی منفی" in qlow or "منفی انبار" in qlow:
        cursor.execute("SELECT name, quantity, unit FROM products WHERE quantity < 0 LIMIT 15")
        rows = cursor.fetchall()
        if not rows:
            show_direct_answer(question, "موجودی منفی وجود ندارد.")
        else:
            lines = ["⚠️ موجودی منفی:"] + [f"• {n}: {q:g} {u}" for n, q, u in rows]
            show_direct_answer(question, "\n".join(lines))
        return

    # ساخت وظیفه سریع: "برای علی وظیفه بساز: ..."
    task_match = re.search(r"برای\s+(علی|موسی|احمد|امید|انباردار|فروشنده|حسابدار|کارپرداز)\s+وظیفه\s*(?:بساز|ایجاد کن|بده)[:\s]*(.+)", qlow)
    if task_match:
        who, title = task_match.group(1), task_match.group(2).strip()
        role = normalize_employee_role(who)
        if title:
            tid = create_manager_task(title[:200], f"ایجادشده از چت توسط {get_active_employee()}", role, source="chat_assistant", priority="medium")
            show_direct_answer(question, f"✅ وظیفه #{tid} برای {who} ({role}) ثبت شد:\n{title}")
            return

    # هشدارهای باز
    if any(k in qlow for k in ("هشدار باز", "هشدارها", "هشدارهای مدیر", "چه هشداری")):
        try:
            rows = get_open_manager_alerts(12)
            if not rows:
                show_direct_answer(question, "هشدار بازی وجود ندارد.")
            else:
                lines = ["هشدارهای باز:"]
                for r in rows:
                    lines.append(f"[{r[2]}] {r[3]} — {r[5] or 'سیستم'}")
                show_direct_answer(question, "\n".join(lines))
        except Exception as e:
            show_direct_answer(question, f"خطا در خواندن هشدارها: {e}")
        return

    # عملکرد کارکنان
    if any(k in qlow for k in ("عملکرد کارکنان", "امتیاز کارکنان", "گزارش عملکرد")):
        try:
            report = get_owner_performance_report(7)
            show_direct_answer(question, report[:2500])
        except Exception as e:
            show_direct_answer(question, f"خطا: {e}")
        return

    # اجرای نظارت
    if any(k in qlow for k in ("نظارت کن", "بررسی هوشمند", "مانیتورینگ", "چک کن سیستم")):
        try:
            n = run_smart_monitoring()
            show_direct_answer(question, f"نظارت انجام شد. {n} هشدار/وظیفه جدید ایجاد شد (در صورت نیاز).")
        except Exception as e:
            show_direct_answer(question, f"خطا در نظارت: {e}")
        return

    # سود امروز
    if any(k in qlow for k in ("سود امروز", "سود خالص", "چقدر سود")):
        today = datetime.now().strftime("%Y-%m-%d")
        cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='income' AND substr(entry_date,1,10)=?", (today,))
        income = float(cursor.fetchone()[0] or 0)
        cursor.execute("SELECT COALESCE(SUM(amount),0) FROM accounting WHERE entry_type='expense' AND substr(entry_date,1,10)=?", (today,))
        expense = float(cursor.fetchone()[0] or 0)
        show_direct_answer(question, f"امروز:\nدرآمد: {income:,.0f}\nهزینه: {expense:,.0f}\nسود تقریبی: {income-expense:,.0f} ریال")
        return


    # =====================================================
    # سؤال معمولی → Ollama
    # =====================================================

    chat.insert(
        tk.END,
        "شما: " +
        question +
        "\n\n"
    )

    conversation.append({
        "role": "user",
        "content": question
    })

    try:

        context = search_files(
            question
        )

        inventory_keywords = [
            "انبار", "موجودی", "کالا", "محصول",
            "قیمت خرید", "قیمت فروش", "موجودی واقعی",
            "چند تا", "چقدر موجود"
        ]

        need_inventory = any(
            keyword in question for keyword in inventory_keywords
        )

        inventory_context = (
            (get_inventory_text() or "")[:1800]
            if need_inventory
            else ""
        )

        profile = get_ai_profile()
        recent_learning = get_recent_ai_learning(3)

        thinking_messages = [
            {
                "role": "system",
                "content": (
                    f"تو دستیار اجرایی فروشگاه هستی (نه فقط چت‌بات). "
                    f"مالک: {profile['owner_name']}. نقش: {profile['role']}. "
                    f"مأموریت: {profile['mission']}. قوانین: {profile['rules']}. "
                    "قوانین پاسخ:\n"
                    "1) کوتاه، عملی و فارسی جواب بده (حداکثر ۸ خط مگر اینکه جزئیات خواسته شود).\n"
                    "2) اطلاعات را حدس نزن؛ فقط از داده واقعی استفاده‌شده در پیام.\n"
                    "3) اگر کاربر دستور کار داد (وظیفه، هشدار، گزارش)، قدم بعدی مشخص بگو.\n"
                    "4) برای تصمیم‌گیری: گزینه + توصیه یک‌خطی بده.\n"
                    "یادگیری اخیر:\n" + (recent_learning or "—")
                )
            }
        ]

        if context:

            thinking_messages.append({
                "role": "system",
                "content": (
                    "اطلاعات مرتبط از فایل‌ها:\n" +
                    context
                )
            })

        if inventory_context:

            thinking_messages.append({
                "role": "system",
                "content": (
                    "موجودی واقعی انبار:\n" +
                    inventory_context
                )
            })

        # فقط ۲ پیام آخر برای سرعت بیشتر
        thinking_messages.extend(
            conversation[-1:]
        )

        response = requests.post(
            "http://localhost:11434/api/chat",
            json={
                "model": get_ai_model(),
                "messages": thinking_messages,
                "stream": False,
                "keep_alive": "2m",
                "options": {
                    "num_predict": 100,
                    "temperature": 0.15,
                    "num_ctx": 1024,
                    "num_thread": 4
                }
            },
            timeout=120
        )

        response.raise_for_status()

        answer = response.json()["message"]["content"]

        chat.insert(
            tk.END,
            "AI: " +
            answer +
            "\n\n"
        )

        chat.see(
            tk.END
        )

        speak_text(
            answer
        )

        conversation.append({
            "role": "assistant",
            "content": answer
        })
        # جلوگیری از رشد بی‌نهایت حافظه مکالمه (سرعت و رم)
        if len(conversation) > 12:
            conversation[:] = conversation[-12:]

        save_memory()

    except Exception as e:

        chat.insert(
            tk.END,
            "❌ خطا: " +
            str(e) +
            "\n\n"
        )

        chat.see(
            tk.END
        )


# =========================================================
# پاک کردن حافظه
# =========================================================

def clear_chat():

    global conversation

    conversation = []

    save_memory()

    chat.delete(
        "1.0",
        tk.END
    )

    chat.insert(
        tk.END,
        "🧠 حافظه گفتگو پاک شد.\n\n"
    )

# =========================================================
# پنل کارمندان و کارپردازی
# =========================================================
def open_employee_tasks_window(employee, parent=None):
    """کارتابل شخصی کارمند: وظایف + هشدار + ثبت کار روزانه + خلاصه امروز."""
    host = parent if parent is not None else window
    role = normalize_employee_role(employee)
    display = EMPLOYEE_DISPLAY.get(role, employee)

    win = tk.Toplevel(host)
    win.title(f"📋 کارتابل — {display}")
    win.geometry("1100x750")

    tk.Label(win, text=f"📋 کارتابل شخصی — {display}", font=("Tahoma", 17, "bold")).pack(pady=8)

    # خلاصه امتیاز و کار امروز
    summary_frame = tk.Frame(win, relief=tk.GROOVE, borderwidth=2)
    summary_frame.pack(fill=tk.X, padx=12, pady=4)
    summary_label = tk.Label(summary_frame, text="در حال بارگذاری...", font=("Tahoma", 11), justify="right")
    summary_label.pack(padx=10, pady=8)

    notebook = ttk.Notebook(win)
    notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=6)

    # ---- تب وظایف ----
    tasks_tab = tk.Frame(notebook)
    notebook.add(tasks_tab, text="📋 وظایف من")

    cols = ("id", "title", "priority", "status", "source", "date")
    tree = ttk.Treeview(tasks_tab, columns=cols, show="headings", height=12)
    heads = {"id": "شناسه", "title": "وظیفه", "priority": "اولویت", "status": "وضعیت", "source": "منبع", "date": "تاریخ"}
    for c in cols:
        tree.heading(c, text=heads[c])
        tree.column(c, width=100 if c != "title" else 360)
    tree.pack(fill=tk.BOTH, expand=True, padx=8, pady=6)

    detail = scrolledtext.ScrolledText(tasks_tab, height=7, wrap=tk.WORD, font=("Tahoma", 10))
    detail.pack(fill=tk.X, padx=8, pady=4)

    def refresh_tasks():
        for item in tree.get_children():
            tree.delete(item)
        for row in get_employee_task_rows(employee, limit=100):
            task_id, title, desc, emp, source, priority, status, due, created = row[:9]
            tree.insert("", tk.END, iid=str(task_id), values=(task_id, title, priority, status, source, due or created))

    def show_detail(_=None):
        sel = tree.selection()
        if not sel:
            return
        row = _task_row(int(sel[0]))
        if not row:
            return
        detail.delete("1.0", tk.END)
        detail.insert(
            tk.END,
            f"عنوان: {row[1]}\n\nتوضیح:\n{row[2] or ''}\n\nنتیجه آخرین اجرا:\n{row[12] or ''}\n\nخطای آخر:\n{row[14] or ''}",
        )

    tree.bind("<<TreeviewSelect>>", show_detail)

    def run_selected():
        sel = tree.selection()
        if not sel:
            messagebox.showwarning("وظیفه", "یک وظیفه را انتخاب کنید.", parent=win)
            return
        try:
            result = execute_employee_task(int(sel[0]), role)
            detail.delete("1.0", tk.END)
            detail.insert(tk.END, result)
            refresh_all()
        except Exception as e:
            messagebox.showerror("خطای اجرا", str(e), parent=win)
            refresh_tasks()

    btn = tk.Frame(tasks_tab)
    btn.pack(pady=6)
    tk.Button(btn, text="🤖 اجرای وظیفه", font=("Tahoma", 11, "bold"), command=run_selected).pack(side=tk.LEFT, padx=5)
    tk.Button(btn, text="🔄 بروزرسانی", command=lambda: refresh_all()).pack(side=tk.LEFT, padx=5)

    # ---- تب ثبت کار روزانه ----
    log_tab = tk.Frame(notebook)
    notebook.add(log_tab, text="✍️ ثبت کار روزانه")

    tk.Label(log_tab, text="کار واقعی امروزت را ثبت کن تا در امتیاز و گزارش مالک لحاظ شود.", font=("Tahoma", 10)).pack(pady=6)

    form = tk.Frame(log_tab)
    form.pack(fill=tk.X, padx=12, pady=6)

    tk.Label(form, text="نوع کار:", font=("Tahoma", 10)).grid(row=0, column=0, padx=4, pady=6, sticky="e")
    work_types = {
        "کارمند انبار": ["بررسی موجودی", "ورود کالا", "خروج کالا", "انبارگردانی", "سایر"],
        "کارمند فروشگاه": ["ثبت فروش", "ثبت مشتری", "پیگیری سفارش", "سایر"],
        "کارمند حسابداری": ["ثبت هزینه", "ثبت سند", "بررسی مغایرت", "تأیید خرید", "سایر"],
        "کارمند کارپرداز": ["ثبت درخواست خرید", "پیگیری تأمین‌کننده", "تحویل کالا", "سایر"],
    }
    work_type_var = tk.StringVar()
    work_combo = ttk.Combobox(form, textvariable=work_type_var, values=work_types.get(role, ["سایر"]), width=28, font=("Tahoma", 10))
    work_combo.grid(row=0, column=1, padx=4, pady=6)
    if work_combo["values"]:
        work_combo.current(0)

    tk.Label(form, text="تعداد:", font=("Tahoma", 10)).grid(row=0, column=2, padx=4, pady=6, sticky="e")
    qty_entry = tk.Entry(form, width=10, font=("Tahoma", 10))
    qty_entry.insert(0, "1")
    qty_entry.grid(row=0, column=3, padx=4, pady=6)

    tk.Label(form, text="واحد:", font=("Tahoma", 10)).grid(row=0, column=4, padx=4, pady=6, sticky="e")
    unit_entry = tk.Entry(form, width=10, font=("Tahoma", 10))
    unit_entry.insert(0, "مورد")
    unit_entry.grid(row=0, column=5, padx=4, pady=6)

    tk.Label(form, text="توضیح:", font=("Tahoma", 10)).grid(row=1, column=0, padx=4, pady=6, sticky="e")
    notes_entry = tk.Entry(form, width=70, font=("Tahoma", 10))
    notes_entry.grid(row=1, column=1, columnspan=5, padx=4, pady=6, sticky="w")

    log_list = ttk.Treeview(log_tab, columns=("date", "type", "qty", "notes"), show="headings", height=10)
    log_list.heading("date", text="تاریخ")
    log_list.heading("type", text="نوع کار")
    log_list.heading("qty", text="تعداد")
    log_list.heading("notes", text="توضیح")
    log_list.column("date", width=100)
    log_list.column("type", width=180)
    log_list.column("qty", width=80)
    log_list.column("notes", width=350)
    log_list.pack(fill=tk.BOTH, expand=True, padx=12, pady=6)

    def refresh_logs():
        for item in log_list.get_children():
            log_list.delete(item)
        for row in get_daily_work_logs(employee, days=14, limit=50):
            lid, emp, wtype, qty, unit, notes, wdate, created = row
            log_list.insert("", tk.END, values=(wdate, wtype, f"{qty:g} {unit}", notes or ""))

    def save_log():
        wtype = work_type_var.get().strip()
        if not wtype:
            messagebox.showwarning("توجه", "نوع کار را انتخاب کنید.", parent=win)
            return
        try:
            qty = float(qty_entry.get().replace(",", "").strip() or 1)
        except ValueError:
            messagebox.showerror("خطا", "تعداد نامعتبر است.", parent=win)
            return
        add_daily_work_log(employee, wtype, qty, unit_entry.get().strip() or "مورد", notes_entry.get().strip())
        notes_entry.delete(0, tk.END)
        qty_entry.delete(0, tk.END)
        qty_entry.insert(0, "1")
        refresh_all()
        messagebox.showinfo("موفق", "کار روزانه ثبت شد.", parent=win)

    tk.Button(form, text="💾 ثبت کار", font=("Tahoma", 10, "bold"), command=save_log).grid(row=0, column=6, padx=8, pady=6)

    # ---- تب هشدارها ----
    alert_tab = tk.Frame(notebook)
    notebook.add(alert_tab, text="⚠️ هشدارهای من")
    alert_text = scrolledtext.ScrolledText(alert_tab, wrap=tk.WORD, font=("Tahoma", 11))
    alert_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    def refresh_all():
        try:
            dash = get_personal_dashboard(employee)
            real_parts = [f"{k}: {v}" for k, v in (dash.get("real_work") or {}).items()]
            summary_label.config(
                text=(
                    f"امتیاز امروز: {dash['score']:.0f}/100  |  فعالیت: {dash['activities_today']}  |  "
                    f"وظایف باز: {len(dash['open_tasks'])}  |  هشدار باز: {len(dash['alerts'])}\n"
                    + ("کار سیستم: " + " | ".join(real_parts) if real_parts else "کار سیستم: —")
                )
            )
            # alerts
            alert_text.config(state=tk.NORMAL)
            alert_text.delete("1.0", tk.END)
            if not dash["alerts"]:
                alert_text.insert(tk.END, "هشدار بازی برای شما وجود ندارد.")
            else:
                for a in dash["alerts"]:
                    alert_text.insert(tk.END, f"[{a[2]}] {a[3]}\n{a[4] or ''}\nزمان: {a[5]}\n{'—' * 40}\n")
            alert_text.config(state=tk.DISABLED)
        except Exception as e:
            summary_label.config(text=f"خطا در بارگذاری کارتابل: {e}")
        refresh_tasks()
        refresh_logs()

    refresh_all()




def open_employee_center_window():
    win = tk.Toplevel(window)
    win.title("👥 کارکنان")
    win.geometry("820x580")
    tk.Label(win, text="👥 مرکز کارکنان واقعی", font=("Tahoma", 18, "bold")).pack(pady=10)
    tk.Label(win, text=f"کاربر فعال: {get_active_employee()}", font=("Tahoma", 11, "bold")).pack(pady=4)

    frame = tk.Frame(win)
    frame.pack(pady=12, fill=tk.X, padx=20)

    employees = [
        ("علی", "انباردار", open_inventory_window),
        ("موسی", "فروشنده", open_store_window),
        ("احمد", "حسابدار", open_chart_of_accounts_window),
        ("امید", "کارپرداز", open_procurement_window),
    ]

    for name, role, cmd in employees:
        row = tk.Frame(frame)
        row.pack(fill=tk.X, pady=6)
        tk.Button(
            row, text=f"{name} — {role}", width=22, font=("Tahoma", 11, "bold"),
            command=lambda n=name, c=cmd: (set_active_employee(n), log_employee_activity(n, "ورود به پنل", role), c()),
        ).pack(side=tk.LEFT, padx=4)
        tk.Button(
            row, text="📋 کارتابل من", font=("Tahoma", 10, "bold"),
            command=lambda n=name: (set_active_employee(n), open_employee_tasks_window(n, win)),
        ).pack(side=tk.LEFT, padx=4)
        tk.Label(row, text=role, font=("Tahoma", 10)).pack(side=tk.LEFT, padx=8)

    owner_frame = tk.Frame(win)
    owner_frame.pack(pady=16)

    def show_performance_report():
        report_win = tk.Toplevel(win)
        report_win.title("📊 گزارش عملکرد کارکنان")
        report_win.geometry("900x650")
        tk.Label(report_win, text="📊 گزارش عملکرد برای مالک", font=("Tahoma", 16, "bold")).pack(pady=8)
        txt = scrolledtext.ScrolledText(report_win, wrap=tk.WORD, font=("Tahoma", 11))
        txt.pack(fill=tk.BOTH, expand=True, padx=12, pady=8)
        try:
            report = get_owner_performance_report(7)
            txt.insert(tk.END, report)
        except Exception as e:
            txt.insert(tk.END, f"خطا: {e}")
        txt.config(state=tk.DISABLED)
        tk.Button(report_win, text="بستن", command=report_win.destroy).pack(pady=6)

    tk.Button(
        owner_frame, text="📊 گزارش عملکرد کارکنان (مالک)", font=("Tahoma", 11, "bold"),
        command=show_performance_report,
    ).pack(side=tk.LEFT, padx=8)

    tk.Button(
        owner_frame, text="← بازنشانی کاربر به مالک",
        command=lambda: (set_active_employee("مالک"), win.destroy()),
        font=("Tahoma", 10),
    ).pack(side=tk.LEFT, padx=8)


def open_purchase_approval_window():
    win = tk.Toplevel(window)
    win.title("💳 تأیید خرید توسط حسابداری — احمد")
    win.geometry("1100x650")

    tk.Label(win, text="💳 درخواست‌های خرید در انتظار تأیید حسابداری", font=("Tahoma", 17, "bold")).pack(pady=10)
    pending_label = tk.Label(win, text="درخواست جدید: 0", font=("Tahoma", 12, "bold"))
    pending_label.pack(pady=2)

    top = tk.Frame(win); top.pack(fill=tk.X, padx=10, pady=5)
    tk.Label(top, text="حساب پرداخت:", font=("Tahoma", 11, "bold")).pack(side=tk.LEFT, padx=5)
    account_var = tk.StringVar()
    account_combo = ttk.Combobox(top, textvariable=account_var, width=45, state="readonly", font=("Tahoma", 11))
    account_combo.pack(side=tk.LEFT, padx=5)
    balance_label = tk.Label(top, text="موجودی: 0", font=("Tahoma", 11, "bold")); balance_label.pack(side=tk.LEFT, padx=10)

    cols=("id","requester","name","qty","price","total","status","date")
    tree=ttk.Treeview(win, columns=cols, show="headings")
    heads={"id":"شناسه","requester":"درخواست‌کننده","name":"کالا","qty":"تعداد","price":"قیمت خرید","total":"مبلغ","status":"وضعیت","date":"تاریخ"}
    for c in cols:
        tree.heading(c,text=heads[c]); tree.column(c,width=110)
    tree.column("name",width=220); tree.pack(fill=tk.BOTH,expand=True,padx=10,pady=10)

    selected_request_label = tk.Label(win, text="درخواست انتخاب نشده", font=("Tahoma", 11, "bold"))
    selected_request_label.pack(pady=3)

    account_map = {}

    def on_request_selected(event=None):
        sel = tree.selection()
        if not sel:
            selected_request_label.config(text="درخواست انتخاب نشده")
            return
        vals = tree.item(sel[0])["values"]
        selected_request_label.config(text=f"درخواست انتخاب‌شده: #{vals[0]} | کالا: {vals[2]} | تعداد: {vals[3]} | مبلغ: {float(vals[5] or 0):,.0f} ریال")

    tree.bind("<<TreeviewSelect>>", on_request_selected)

    def load_accounts():
        # حسابدار باید بتواند هر حساب دارای موجودی را برای پرداخت انتخاب کند؛
        # محدود کردن به نام های ثابت مثل «صندوق» و «بانک» باعث می شد حساب های
        # ساخته شده توسط کاربر در فهرست نمایش داده نشوند.
        account_map.clear()
        cursor.execute("SELECT name, COALESCE(balance,0) FROM accounts WHERE account_type='دارایی' ORDER BY name")
        rows=cursor.fetchall()
        values=[]
        for name,balance in rows:
            name=str(name)
            account_map[name]=float(balance or 0)
            values.append(f"{name} — موجودی: {float(balance or 0):,.0f}")
        account_combo["values"]=values
        if values:
            account_combo.current(0)
        else:
            account_var.set("")
        update_balance()

    def get_selected_account_name():
        text=account_var.get().strip()
        if not text:
            return ""
        return text.split(" — موجودی:",1)[0].strip()

    def update_balance(event=None):
        name=get_selected_account_name()
        if not name:
            balance_label.config(text="موجودی: 0"); return
        balance=account_map.get(name)
        if balance is None:
            cursor.execute("SELECT balance FROM accounts WHERE name=?",(name,)); r=cursor.fetchone()
            balance=float(r[0] or 0) if r else 0
        balance_label.config(text=f"موجودی: {balance:,.0f}")
    account_combo.bind("<<ComboboxSelected>>", update_balance)

    tk.Label(win, text="برای انتخاب درخواست روی ردیف آن کلیک کنید، سپس حساب پرداخت را انتخاب و تأیید کنید.", font=("Tahoma", 10)).pack(pady=2)

    def refresh():
        for item in tree.get_children(): tree.delete(item)
        cursor.execute("SELECT id,employee,product_name,quantity,unit_price,total,status,request_date FROM purchase_requests WHERE approval_status IN ('در انتظار تایید حسابداری','در انتظار تایید مجدد حسابداری') OR status IN ('در انتظار تایید حسابداری','در انتظار تایید مجدد حسابداری') ORDER BY id DESC")
        rows = cursor.fetchall()
        for r in rows: tree.insert("",tk.END,values=r)
        pending_label.config(text=f"درخواست جدید: {len(rows)}")
        load_accounts()

    def approve(accept=True):
        sel=tree.selection()
        if not sel:
            messagebox.showwarning("توجه","ابتدا یک درخواست را انتخاب کنید."); return
        account=get_selected_account_name()
        if not account:
            messagebox.showwarning("توجه","ابتدا حساب پرداخت را از فهرست انتخاب کنید."); return
        vals=tree.item(sel[0])["values"]; rid=int(vals[0]); total=float(vals[5]); now=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        if accept:
            cursor.execute("SELECT account_type FROM accounts WHERE name=?",(account,)); r=cursor.fetchone()
            if not r or r[0] != 'دارایی':
                messagebox.showerror("حساب نامعتبر","حساب پرداخت باید از نوع دارایی باشد."); return
            cursor.execute("UPDATE purchase_requests SET approval_status='تایید حسابداری', status='تایید حسابداری', approved_by=?, approved_at=?, payment_account=?, approved_unit_price=unit_price, approved_total=total, price_changed_by=NULL, price_changed_at=NULL WHERE id=?",("احمد",now,account,rid))
            log_employee_activity("احمد","تأیید درخواست خرید",f"درخواست {rid} | حساب {account} | مبلغ {total:,.0f} ریال")
            conn.commit(); messagebox.showinfo("تأیید شد","درخواست به پنل کارپرداز امید ارسال شد.")
        else:
            cursor.execute("UPDATE purchase_requests SET approval_status='رد حسابداری', status='رد حسابداری', approved_by=?, approved_at=? WHERE id=?",("احمد",now,rid))
            log_employee_activity("احمد","رد درخواست خرید",f"درخواست {rid}"); conn.commit(); messagebox.showinfo("رد شد","درخواست خرید رد شد.")
        refresh()

    btn=tk.Frame(win); btn.pack(pady=8)
    tk.Button(btn,text="✅ تأیید و ارسال به کارپرداز",font=("Tahoma",11,"bold"),command=lambda:approve(True)).pack(side=tk.LEFT,padx=6)
    tk.Button(btn,text="❌ رد درخواست",font=("Tahoma",11),command=lambda:approve(False)).pack(side=tk.LEFT,padx=6)
    tk.Button(btn,text="🔄 بروزرسانی",font=("Tahoma",11),command=refresh).pack(side=tk.LEFT,padx=6)
    refresh()

    def auto_refresh_requests():
        if win.winfo_exists():
            refresh()
            win.after(5000, auto_refresh_requests)
    win.after(5000, auto_refresh_requests)


def open_procurement_window():
    win=tk.Toplevel(window); win.title('🧾 کارپردازی — امید'); win.geometry('1150x720')
    tk.Label(win,text='🧾 کارپردازی | امید',font=('Tahoma',18,'bold')).pack(pady=10)
    tk.Label(win,text='درخواست تأییدشده را انتخاب کن، قیمت واقعی خرید را وارد کن و خرید را ثبت کن.',font=('Tahoma',10)).pack(pady=3)
    form=tk.Frame(win); form.pack(fill=tk.X,padx=10,pady=8)
    labels=['تأمین‌کننده واقعی','کد کالا','نام کالا','تعداد','قیمت تأییدشده','قیمت واقعی خرید','توضیحات']; entries=[]
    for i,lbl in enumerate(labels):
        tk.Label(form,text=lbl,font=('Tahoma',10,'bold')).grid(row=0,column=i,padx=3,pady=3)
        e=tk.Entry(form,width=15,font=('Tahoma',10)); e.grid(row=1,column=i,padx=3,pady=3); entries.append(e)
    supplier_e,code_e,name_e,qty_e,approved_price_e,price_e,notes_e=entries
    status_label=tk.Label(win,text='درخواستی انتخاب نشده است.',font=('Tahoma',11,'bold')); status_label.pack(pady=4)
    cols=('id','supplier','code','name','qty','approved_price','price','total','status','date')
    tree=ttk.Treeview(win,columns=cols,show='headings',selectmode='browse')
    heads={'id':'شناسه','supplier':'تأمین‌کننده','code':'کد','name':'کالا','qty':'تعداد','approved_price':'قیمت تأییدشده','price':'قیمت فعلی','total':'مبلغ فعلی','status':'وضعیت','date':'تاریخ'}
    for c in cols: tree.heading(c,text=heads[c]); tree.column(c,width=105)
    tree.column('name',width=170); tree.column('supplier',width=140); tree.pack(fill=tk.BOTH,expand=True,padx=10,pady=10)
    def clear_form():
        for e in entries: e.delete(0,tk.END)
        status_label.config(text='درخواستی انتخاب نشده است.')
    def set_entry(e,value):
        e.delete(0,tk.END)
        if value is not None: e.insert(0,str(value))
    def on_select(event=None):
        sel=tree.selection()
        if not sel: return
        rid=int(tree.item(sel[0])['values'][0])
        cursor.execute('SELECT supplier_name,product_code,product_name,quantity,unit_price,total,approved_unit_price,approved_total,notes,payment_account FROM purchase_requests WHERE id=?',(rid,))
        r=cursor.fetchone()
        if not r: return
        supplier,code,name,qty,unit_price,total,approved_price,approved_total,notes,payment_account=r
        set_entry(supplier_e,supplier or ''); set_entry(code_e,code or ''); set_entry(name_e,name or ''); set_entry(qty_e,qty or 0)
        set_entry(approved_price_e,approved_price if approved_price is not None else unit_price or 0); set_entry(price_e,unit_price or 0); set_entry(notes_e,notes or '')
        status_label.config(text=f'درخواست #{rid} | حساب پرداخت: {payment_account or "---"} | مبلغ تأییدشده: {float(approved_total if approved_total is not None else total or 0):,.0f} ریال')
    tree.bind('<<TreeviewSelect>>',on_select)
    def refresh():
        for item in tree.get_children(): tree.delete(item)
        cursor.execute("SELECT id,supplier_name,product_code,product_name,quantity,COALESCE(approved_unit_price,unit_price,0),COALESCE(unit_price,0),COALESCE(total,0),status,request_date FROM purchase_requests WHERE approval_status='تایید حسابداری' AND status='تایید حسابداری' ORDER BY id DESC")
        rows=cursor.fetchall()
        for r in rows: tree.insert('',tk.END,values=r)
        if not rows: clear_form()
    def complete_purchase():
        sel=tree.selection()
        if not sel: messagebox.showwarning('توجه','ابتدا یک درخواست را از جدول انتخاب کنید.'); return
        rid=int(tree.item(sel[0])['values'][0])
        try:
            supplier=supplier_e.get().strip(); code=code_e.get().strip(); name=name_e.get().strip(); qty=float(qty_e.get() or 0); actual_price=float(price_e.get() or 0); notes=notes_e.get().strip()
            if not name or qty<=0 or actual_price<=0: raise ValueError('نام کالا، تعداد و قیمت واقعی خرید را کامل وارد کنید.')
            cursor.execute('SELECT approval_status,status,payment_account,approved_unit_price,approved_total FROM purchase_requests WHERE id=?',(rid,)); row=cursor.fetchone()
            if not row: raise ValueError('درخواست خرید پیدا نشد.')
            approval_status,status,payment_account,db_approved_price,db_approved_total=row
            if approval_status!='تایید حسابداری' or status!='تایید حسابداری': raise ValueError('این درخواست در حال حاضر مجوز خرید ندارد.')
            approved_price=float(db_approved_price or 0); actual_total=round(qty*actual_price,2)
            if round(actual_price,2)!=round(approved_price,2):
                now=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                cursor.execute("UPDATE purchase_requests SET supplier_name=?,product_code=?,product_name=?,quantity=?,unit_price=?,total=?,notes=?,approval_status='در انتظار تایید مجدد حسابداری',status='در انتظار تایید مجدد حسابداری',price_changed_by='امید',price_changed_at=? WHERE id=?",(supplier,code,name,qty,actual_price,actual_total,notes,now,rid))
                conn.commit(); log_employee_activity('امید','تغییر قیمت و ارسال مجدد برای حسابداری',f'درخواست {rid} | {approved_price:,.0f} -> {actual_price:,.0f} ریال'); refresh()
                messagebox.showinfo('نیاز به تأیید مجدد',f'قیمت تأییدشده: {approved_price:,.0f} ریال\nقیمت جدید: {actual_price:,.0f} ریال\n\nخرید انجام نشد و درخواست دوباره برای حسابداری ارسال شد.'); return
            cursor.execute('SELECT balance FROM accounts WHERE name=?',(payment_account,)); account_row=cursor.fetchone()
            if not account_row: raise ValueError(f'حساب پرداخت «{payment_account}» پیدا نشد.')
            balance=float(account_row[0] or 0)
            if not payment_account or not str(payment_account).strip():
                raise ValueError('برای این درخواست حساب پرداخت تعیین نشده است. ابتدا آن را به حسابداری برگردانید.')
            cursor.execute("SELECT account_type FROM accounts WHERE name=?",(payment_account,)); at=cursor.fetchone()
            if not at or at[0] != 'دارایی': raise ValueError('حساب پرداخت باید از نوع دارایی باشد.')
            # جلوگیری قطعی از ثبت دوباره یک درخواست خرید
            cursor.execute("SELECT COUNT(*) FROM purchases WHERE request_id=?", (rid,))
            existing_purchase_count = int(cursor.fetchone()[0] or 0)
            cursor.execute("SELECT COUNT(*) FROM ledger_entries WHERE ref_type='purchase' AND ref_id=?", (rid,))
            existing_ledger_count = int(cursor.fetchone()[0] or 0)

            if existing_purchase_count > 0 or existing_ledger_count > 0:
                if existing_purchase_count > 0:
                    cursor.execute("UPDATE purchase_requests SET status='خرید انجام شد', approval_status='خرید انجام شد' WHERE id=?", (rid,))
                    conn.commit()
                    refresh()
                    raise ValueError(
                        f"درخواست خرید شماره {rid} قبلاً ثبت و پرداخت شده است.\n"
                        "برای جلوگیری از کسر دوباره پول، ثبت مجدد انجام نشد."
                    )
                else:
                    conn.rollback()
                    raise ValueError(
                        f"برای درخواست خرید شماره {rid} قبلاً سند مالی ثبت شده است.\n"
                        "برای جلوگیری از کسر دوباره موجودی حساب، خرید مجدد انجام نشد.\n"
                        "این درخواست نیاز به بررسی مدیر دارد."
                    )

            purchase_date=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            post_simple('موجودی کالا',payment_account,actual_total,
                        description=f'خرید {name} از {supplier or "بدون تأمین‌کننده"}',
                        ref_type='purchase',ref_id=rid,entry_date=purchase_date,employee='امید',commit=False)
            cursor.execute('SELECT id,quantity,COALESCE(avg_buy_price,buy_price,0) FROM products WHERE code=?',(code,)); prod=cursor.fetchone()
            if prod:
                pid,old_qty,old_avg=prod; old_qty=float(old_qty or 0); old_avg=float(old_avg or 0); new_qty=old_qty+qty
                new_avg=((old_qty*old_avg)+(qty*actual_price))/new_qty if new_qty>0 else actual_price
                cursor.execute('UPDATE products SET quantity=quantity+?,buy_price=?,avg_buy_price=? WHERE id=?',(qty,actual_price,new_avg,pid))
            else:
                if not code: raise ValueError('برای کالای جدید کد کالا لازم است.')
                cursor.execute('INSERT INTO products(code,name,quantity,buy_price,avg_buy_price,sell_price,unit,category) VALUES(?,?,?,?,?,?,?,?)',(code,name,qty,actual_price,actual_price,0,'عدد','خوراکی'))
            cursor.execute('INSERT INTO purchases(request_id,supplier_name,product_code,product_name,quantity,unit_price,total,purchase_date,employee) VALUES(?,?,?,?,?,?,?,?,?)',(rid,supplier,code,name,qty,actual_price,actual_total,purchase_date,'امید'))
            cursor.execute("UPDATE purchase_requests SET status='خرید انجام شد',approval_status='خرید انجام شد' WHERE id=?",(rid,)); conn.commit()
            log_employee_activity('امید','ثبت خرید نهایی',f'درخواست {rid} | {name} | {actual_total:,.0f} ریال'); refresh()
            messagebox.showinfo('خرید انجام شد',f'خرید با موفقیت انجام شد.\nمبلغ: {actual_total:,.0f} ریال\nاز حساب: {payment_account}\nتعداد: {qty:g}\n\nموجودی انبار افزایش یافت و مبلغ از حساب پرداخت کسر شد.')
        except Exception as e:
            conn.rollback(); messagebox.showerror('خطا',str(e))
    btns=tk.Frame(win); btns.pack(pady=6)
    tk.Button(btns,text='✅ ثبت خرید و ورود به انبار',command=complete_purchase,font=('Tahoma',11,'bold')).pack(side=tk.LEFT,padx=5)
    def return_to_accounting():
        sel=tree.selection()
        if not sel:
            messagebox.showwarning('توجه','ابتدا درخواست را انتخاب کنید.'); return
        rid=int(tree.item(sel[0])['values'][0])
        if not messagebox.askyesno('برگشت به حسابداری',f'درخواست #{rid} برای تأیید مجدد به حسابداری برگردد؟'):
            return
        try:
            cursor.execute("SELECT status FROM purchase_requests WHERE id=?",(rid,)); rr=cursor.fetchone()
            if not rr: raise ValueError('درخواست پیدا نشد.')
            if rr[0]=='خرید انجام شد': raise ValueError('این درخواست قبلاً خرید شده و قابل برگشت نیست.')
            cursor.execute("UPDATE purchase_requests SET approval_status='در انتظار تایید حسابداری', status='در انتظار تایید حسابداری', payment_account=NULL, approved_by=NULL, approved_at=NULL WHERE id=?",(rid,))
            conn.commit(); log_employee_activity('امید','برگشت درخواست به حسابداری',f'درخواست {rid}')
            refresh(); clear_form()
        except Exception as e:
            conn.rollback(); messagebox.showerror('خطا',str(e))
    tk.Button(btns,text='↩️ برگشت به حسابداری',command=return_to_accounting).pack(side=tk.LEFT,padx=5)
    tk.Button(btns,text='🔄 بروزرسانی',command=refresh).pack(side=tk.LEFT,padx=5)
    tk.Button(btns,text='🧹 پاک کردن فرم',command=clear_form).pack(side=tk.LEFT,padx=5)
    refresh()

# =========================================================
# پاک‌سازی کامل اطلاعات آزمایشی
# =========================================================

def reset_all_test_data():
    """پاک‌سازی اطلاعات واردشده برای شروع دوباره آزمون، بدون حذف ساختار برنامه."""
    global conversation, files_data

    warning = (
        "⚠️ هشدار بسیار مهم\n\n"
        "این عملیات اطلاعات آزمایشی واردشده را از دیتابیس پاک می‌کند، از جمله:\n"
        "• کالاها و موجودی انبار\n"
        "• فروش‌ها و مشتریان\n"
        "• درخواست‌های خرید و خریدهای ثبت‌شده\n"
        "• گردش حساب‌ها و اسناد حسابداری\n"
        "• هزینه‌ها و فعالیت‌های کارکنان\n"
        "• وظایف، هشدارها و سوابق آموزشی آزمایشی\n"
        "• گفت‌وگوی فعلی و حافظه آزمایشی هوش مصنوعی\n\n"
        "حافظه اصلی هویتی برنامه و اطلاعات خالق حذف نمی‌شود.\n"
        "ساختار برنامه، کارکنان پایه و حساب‌های پایه دوباره ایجاد می‌شوند.\n"
        "این عملیات قابل برگشت نیست.\n\n"
        "آیا مطمئن هستید؟"
    )
    if not messagebox.askyesno("پاک‌سازی کامل اطلاعات آزمایشی", warning, icon='warning'):
        return

    # تأیید دوم برای جلوگیری از پاک شدن ناخواسته اطلاعات
    if not messagebox.askyesno(
        "تأیید نهایی",
        "آخرین هشدار: تمام اطلاعات آزمایشی حذف می‌شود.\n\nواقعاً ادامه می‌دهید؟",
        icon='warning'
    ):
        return

    tables_to_clear = [
        'sales', 'customers', 'suppliers', 'purchase_requests', 'purchases',
        'accounting', 'ledger_entries', 'products',
        'employee_activity', 'employee_issues', 'employee_reviews',
        'employee_training', 'employee_learning_progress',
        'ai_learning', 'ai_manager_history', 'ai_email_insights',
        'ai_code_suggestions', 'manager_tasks', 'manager_alerts'
    ]

    try:
        conn.execute('BEGIN')

        for table in tables_to_clear:
            # جدول‌ها در خود برنامه ایجاد شده‌اند؛ نام‌ها ثابت و امن هستند.
            conn.execute(f'DELETE FROM "{table}"')

        # کارکنان ساخته‌شده توسط کاربر حذف می‌شوند و کارکنان پایه برمی‌گردند.
        conn.execute('DELETE FROM employees')
        base_employees = [
            ('علی', 'انباردار'),
            ('موسی', 'فروشنده'),
            ('احمد', 'حسابدار'),
            ('امید', 'کارپرداز'),
            ('مالک', 'مالک سیستم')
        ]
        conn.executemany(
            'INSERT INTO employees(name, role, active) VALUES(?,?,1)',
            base_employees
        )

        # همه حساب‌های آزمایشی حذف و حساب‌های پایه دوباره ساخته می‌شوند.
        conn.execute('DELETE FROM accounts')
        for acc_name, acc_type, acc_side in base_accounts:
            conn.execute(
                'INSERT INTO accounts(name, account_type, balance, normal_side) VALUES(?,?,0,?)',
                (acc_name, acc_type, acc_side)
            )

        # کارمند فعال به مالک برگردد.
        conn.execute(
            "INSERT OR REPLACE INTO app_settings(key,value) VALUES('active_employee','مالک')"
        )

        # پروفایل مدیریتی به حالت اولیه برگردد؛ هویت خالق حفظ می‌شود.
        core = get_core_memory()
        conn.execute('DELETE FROM ai_profile')
        conn.execute("""
            INSERT INTO ai_profile (id, owner_name, role, mission, rules, updated_at)
            VALUES (1, ?, ?, ?, ?, ?)
        """, (
            core.get("creator_name", CREATOR_NAME),
            'خالق و مالک اصلی سیستم',
            'نظارت بر انبار، فروشگاه، حسابداری و کارکنان و کمک به مالک در تصمیم‌گیری',
            'مالک سیستم بالاترین سطح اختیار را دارد. اطلاعات را حدس نزن. تصمیم‌های حساس را بدون تأیید مالک اجرا نکن.',
            datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        ))

        # شماره‌های خودکار جدول‌های آزمایشی از ابتدا شروع شوند.
        for table in tables_to_clear + ['employees', 'accounts', 'ai_profile']:
            try:
                conn.execute("DELETE FROM sqlite_sequence WHERE name=?", (table,))
            except sqlite3.OperationalError:
                pass

        conn.commit()

        # حافظه محلی هوش مصنوعی و وضعیت گفت‌وگو هم پاک شود.
        conversation = []
        files_data = []
        ensure_core_memory()
        try:
            if os.path.exists(MEMORY_FILE):
                with open(MEMORY_FILE, 'w', encoding='utf-8') as f:
                    json.dump([], f, ensure_ascii=False, indent=2)
        except Exception:
            pass

        # لیست فایل‌های رابط کاربری را هم خالی کن.
        try:
            if 'file_list' in globals() and file_list.winfo_exists():
                file_list.delete(0, tk.END)
            if 'file_count_label' in globals() and file_count_label.winfo_exists():
                file_count_label.config(text='تعداد فایل‌ها: 0')
            if 'chat' in globals() and chat.winfo_exists():
                chat.delete('1.0', tk.END)
        except Exception:
            pass

        messagebox.showinfo(
            'پاک‌سازی انجام شد',
            'تمام اطلاعات آزمایشی پاک شد.\n\n'
            'حساب‌ها و کارکنان پایه دوباره ایجاد شدند و موجودی حساب‌ها صفر است.\n'
            'اکنون می‌توانید آزمون را از ابتدا شروع کنید.'
        )

    except Exception as e:
        try:
            conn.rollback()
        except Exception:
            pass
        messagebox.showerror('خطا در پاک‌سازی', f'پاک‌سازی کامل انجام نشد:\n{e}')


# =========================================================
# پنجره اصلی
# =========================================================

window = tk.Tk()

window.title(
    "🤖 هوش مصنوعی محلی + 📦 انبار + 🛒 فروشگاه"
)

window.geometry(
    "1000x780"
)


# =========================================================
# عنوان
# =========================================================

title = tk.Label(
    window,
    text="🤖 هوش مصنوعی + 📦 انبار + 🛒 فروشگاه",
    font=("Tahoma", 18, "bold")
)

title.pack(
    pady=10
)


# =========================================================
# دکمه‌های اصلی
# =========================================================

main_buttons = tk.Frame(
    window
)

main_buttons.pack(
    pady=5
)

# ردیف دکمه‌های پایینی
bottom_frame = tk.Frame(window)
bottom_frame.pack(pady=5)

inventory_button = tk.Button(
    main_buttons,
    text="📦 باز کردن انبار",
    font=("Tahoma", 12, "bold"),
    command=open_inventory_window
)

inventory_button.pack(
    side=tk.LEFT,
    padx=8
)

store_button = tk.Button(
    main_buttons,
    text="🛒 باز کردن فروشگاه",
    font=("Tahoma", 12, "bold"),
    command=open_store_window
)

store_button.pack(
    side=tk.LEFT,
    padx=8
)

email_button = tk.Button(
    window,
    text="✉️ ایمیل هوشمند",
    font=("Tahoma", 11),
    command=open_email_window
)
email_button.pack(side=tk.RIGHT, padx=5)

manager_button = tk.Button(
    main_buttons,
    text="👔 مدیر هوش مصنوعی",
    font=("Tahoma", 12, "bold"),
    command=open_manager_window
)
manager_button.pack(side=tk.LEFT, padx=8)

task_center_button = tk.Button(
    bottom_frame,
    text="📋 وظایف",
    font=("Tahoma", 11, "bold"),
    command=open_task_center_window
)
task_center_button.pack(side=tk.LEFT, padx=8)

tk.Button(bottom_frame, text='👥 کارکنان', font=('Tahoma',11,'bold'), command=open_employee_center_window).pack(side=tk.LEFT,padx=8)

roles_label = tk.Label(
    window,
    text="👷 انباردار  |  🛒 فروشنده  |  💼 حسابدار  |  👔 مدیر هوش مصنوعی",
    font=("Tahoma", 10, "bold")
)
roles_label.pack(pady=(0, 8))

accounting_button = tk.Button(
    main_buttons,
    text="💼 حسابداری",
    font=("Tahoma", 12, "bold"),
    command=open_chart_of_accounts_window
)

accounting_button.pack(
    side=tk.LEFT,
    padx=8
)

reset_test_button = tk.Button(
    main_buttons,
    text="🧹 پاک‌سازی اطلاعات آزمایشی",
    font=("Tahoma", 11, "bold"),
    fg="red",
    command=reset_all_test_data
)
reset_test_button.pack(side=tk.LEFT, padx=8)

voice_test_button = tk.Button(main_buttons, text="🔊 تست صدا", font=("Tahoma", 11, "bold"), command=test_voice)
voice_test_button.pack(side=tk.LEFT, padx=8)


# =========================================================
# فایل‌ها
# =========================================================

files_frame = tk.Frame(
    window,
    relief=tk.GROOVE,
    borderwidth=2
)

files_frame.pack(
    padx=15,
    pady=5,
    fill=tk.X
)

files_title = tk.Label(
    files_frame,
    text="📚 فایل‌های من",
    font=("Tahoma", 12, "bold")
)

files_title.pack(
    pady=5
)

file_count_label = tk.Label(
    files_frame,
    text="تعداد فایل‌ها: 0",
    font=("Tahoma", 10)
)

file_count_label.pack(
    pady=2
)

file_list = tk.Listbox(
    files_frame,
    height=4,
    font=("Tahoma", 11)
)

file_list.pack(
    padx=10,
    pady=5,
    fill=tk.X
)

remove_file_button = tk.Button(
    files_frame,
    text="❌ حذف فایل انتخاب‌شده",
    font=("Tahoma", 10),
    command=remove_selected_file
)

remove_file_button.pack(
    pady=3
)


# =========================================================
# گفتگو
# =========================================================

chat = scrolledtext.ScrolledText(
    window,
    wrap=tk.WORD,
    font=("Tahoma", 12),
    padx=10,
    pady=10
)

chat.pack(
    padx=15,
    pady=10,
    fill=tk.BOTH,
    expand=True
)


# =========================================================
# ورودی
# =========================================================

entry = tk.Entry(
    window,
    font=("Tahoma", 13)
)

entry.pack(
    padx=15,
    pady=5,
    fill=tk.X
)


# =========================================================
# ارسال
# =========================================================

send_button = tk.Button(
    window,
    text="ارسال 🚀",
    font=("Tahoma", 12),
    command=send_message
)

send_button.pack(
    pady=5
)


# =========================================================
# انتخاب فایل
# =========================================================

file_button = tk.Button(
    window,
    text="📚 انتخاب چند PDF یا Word",
    font=("Tahoma", 11),
    command=open_files
)

file_button.pack(
    pady=5
)


# =========================================================
# پاک کردن فایل‌ها
# =========================================================

clear_files_button = tk.Button(
    window,
    text="🗑️ پاک کردن همه فایل‌ها",
    font=("Tahoma", 11),
    command=clear_files
)

clear_files_button.pack(
    pady=5
)


# =========================================================
# حافظه
# =========================================================

def open_ai_brain_window():
    brain_window = tk.Toplevel(window)
    brain_window.title("🧠 مغز و هویت هوش مصنوعی")
    brain_window.geometry("980x700")

    tk.Label(brain_window, text="🧠 مغز مدیریتی هوش مصنوعی", font=("Tahoma", 18, "bold")).pack(pady=8)

    notebook = ttk.Notebook(brain_window)
    notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=8)

    # =====================================================
    # تب ۱: پروفایل، یادگیری و خوداصلاحی قوانین
    # =====================================================

    profile_tab = tk.Frame(notebook)
    notebook.add(profile_tab, text="🧠 پروفایل و یادگیری")

    profile = get_ai_profile()
    tk.Label(
        profile_tab,
        text=f"👑 خالق و مالک سیستم: {profile['owner_name']}",
        font=("Tahoma", 12, "bold")
    ).pack(pady=4)
    tk.Label(
        profile_tab,
        text=f"کد ملی خالق: {profile.get('creator_national_id', CREATOR_NATIONAL_ID)} | حافظه اصلی حذف نمی‌شود",
        font=("Tahoma", 10, "bold")
    ).pack(pady=2)

    profile_text = scrolledtext.ScrolledText(profile_tab, wrap=tk.WORD, font=("Tahoma", 11), height=20)
    profile_text.pack(fill=tk.BOTH, expand=True, padx=12, pady=6)

    def refresh_profile_text():
        p = get_ai_profile()
        recent_learning = get_recent_ai_learning(12)
        history = get_manager_history(5)
        profile_text.config(state=tk.NORMAL)
        profile_text.delete("1.0", tk.END)
        profile_text.insert(tk.END, f"نقش: {p['role']}\n\nمأموریت: {p['mission']}\n\nقوانین فعلی: {p['rules']}\n\n")
        profile_text.insert(tk.END, "================ یادگیری‌های اخیر ================\n")
        profile_text.insert(tk.END, recent_learning or "هنوز یادگیری ثبت نشده است.")
        profile_text.insert(tk.END, "\n\n================ سوابق مدیریتی ================\n")
        profile_text.insert(tk.END, history or "هنوز سابقه مدیریتی ثبت نشده است.")
        profile_text.config(state=tk.DISABLED)

    refresh_profile_text()

    def run_self_evolve():
        evolve_button.config(state=tk.DISABLED, text="⏳ در حال بازبینی تجربه‌ها...")

        def worker():
            try:
                evolve_ai_rules_from_experience()
                brain_window.after(0, lambda: (
                    refresh_profile_text(),
                    messagebox.showinfo("موفق", "قوانین رفتاری AI بر اساس تجربه‌های اخیر به‌روزرسانی شد.")
                ))
            except Exception as e:
                brain_window.after(0, lambda: messagebox.showerror("خطا", f"خطا در خوداصلاحی: {e}"))
            finally:
                brain_window.after(0, lambda: evolve_button.config(state=tk.NORMAL, text="🔄 به‌روزرسانی رفتار AI از تجربه"))

        threading.Thread(target=worker, daemon=True).start()

    evolve_button = tk.Button(
        profile_tab, text="🔄 به‌روزرسانی رفتار AI از تجربه",
        font=("Tahoma", 11, "bold"), command=run_self_evolve
    )
    evolve_button.pack(pady=8)

    # =====================================================
    # تب ۲: ارتقای مدل (Ollama)
    # =====================================================

    model_tab = tk.Frame(notebook)
    notebook.add(model_tab, text="🚀 ارتقای مدل")

    tk.Label(
        model_tab,
        text=f"مدل فعلی: {get_ai_model()}",
        font=("Tahoma", 12, "bold")
    ).pack(pady=8)
    current_model_label = model_tab.winfo_children()[-1]

    models_frame = tk.Frame(model_tab)
    models_frame.pack(fill=tk.BOTH, expand=True, padx=12, pady=6)

    model_columns = ("name", "size", "params")
    model_table = ttk.Treeview(models_frame, columns=model_columns, show="headings", height=10)
    model_table.heading("name", text="نام مدل")
    model_table.heading("size", text="حجم")
    model_table.heading("params", text="تعداد پارامتر")
    model_table.column("name", width=280)
    model_table.column("size", width=150)
    model_table.column("params", width=150)
    model_table.pack(fill=tk.BOTH, expand=True)

    def refresh_models():
        for item in model_table.get_children():
            model_table.delete(item)
        try:
            models = list_ollama_models()
        except ValueError as e:
            messagebox.showerror("خطا", str(e))
            return
        if not models:
            messagebox.showinfo("توجه", "هیچ مدلی روی Ollama نصب نیست.")
            return
        for name, size, params in sorted(models, key=lambda m: m[1], reverse=True):
            size_gb = size / (1024 ** 3) if size else 0
            model_table.insert("", tk.END, values=(name, f"{size_gb:.1f} GB", params or "-"))

    def use_selected_model():
        selection = model_table.selection()
        if not selection:
            messagebox.showwarning("توجه", "ابتدا یک مدل را از لیست انتخاب کنید.")
            return
        name = model_table.item(selection[0])["values"][0]
        set_ai_model(name)
        current_model_label.config(text=f"مدل فعلی: {name}")
        messagebox.showinfo("موفق", f"مدل هوش مصنوعی به «{name}» تغییر کرد.")

    def use_largest_model():
        try:
            models = list_ollama_models()
        except ValueError as e:
            messagebox.showerror("خطا", str(e))
            return
        if not models:
            messagebox.showinfo("توجه", "هیچ مدلی روی Ollama نصب نیست.")
            return
        best = max(models, key=lambda m: m[1])
        set_ai_model(best[0])
        current_model_label.config(text=f"مدل فعلی: {best[0]}")
        messagebox.showinfo("موفق", f"مدل به بزرگ‌ترین مدل نصب‌شده «{best[0]}» ارتقا یافت.")

    model_buttons = tk.Frame(model_tab)
    model_buttons.pack(fill=tk.X, padx=12, pady=6)
    tk.Button(model_buttons, text="🔄 بررسی مدل‌های نصب‌شده", font=("Tahoma", 10), command=refresh_models).pack(side=tk.LEFT, padx=5)
    tk.Button(model_buttons, text="✅ استفاده از مدل انتخاب‌شده", font=("Tahoma", 10, "bold"), command=use_selected_model).pack(side=tk.LEFT, padx=5)
    tk.Button(model_buttons, text="⚡ ارتقا به بزرگ‌ترین مدل نصب‌شده", font=("Tahoma", 10, "bold"), command=use_largest_model).pack(side=tk.LEFT, padx=5)

    tk.Label(
        model_tab,
        text="نکته: مدل جدید باید از قبل با دستور «ollama pull <نام مدل>» نصب شده باشد.",
        font=("Tahoma", 9), fg="gray"
    ).pack(pady=4)

    # =====================================================
    # تب ۳: 🧑‍💻 خودنویس کد
    # =====================================================
    coder_tab = tk.Frame(notebook)
    notebook.add(coder_tab, text="🧑‍💻 خودنویس کد")
    tk.Label(coder_tab, text="AI یک تابع را انتخاب می‌کند، کد جدید می‌نویسد، نسخه پشتیبان می‌سازد و قبل از اعمال py_compile می‌کند.", font=("Tahoma",10), wraplength=900).pack(pady=8)
    coder_frame=tk.Frame(coder_tab); coder_frame.pack(fill=tk.X,padx=12,pady=5)
    tk.Label(coder_frame,text="چه چیزی بهتر شود؟",font=("Tahoma",10,"bold")).pack(side=tk.LEFT,padx=5)
    coder_topic_entry=tk.Entry(coder_frame,width=75,font=("Tahoma",10)); coder_topic_entry.pack(side=tk.LEFT,padx=5,fill=tk.X,expand=True)
    coder_log=scrolledtext.ScrolledText(coder_tab,wrap=tk.WORD,font=("Consolas",10),height=22); coder_log.pack(fill=tk.BOTH,expand=True,padx=12,pady=8)
    def run_self_coder():
        if get_active_employee() not in ('مالک', CREATOR_NAME, 'امید'):
            messagebox.showerror('دسترسی','فقط مالک سیستم می‌تواند عامل برنامه‌نویس خودکار را اجرا کند.'); return
        topic=coder_topic_entry.get().strip()
        if not topic:
            messagebox.showwarning('موضوع لازم است','مثلاً: مشکل ثبت هزینه حسابداری را اصلاح کن.'); return
        if not messagebox.askyesno('تأیید خوداصلاحی','نسخه پشتیبان ساخته می‌شود و فقط بعد از تست موفق کد جدید اعمال می‌شود. ادامه؟'): return
        run_coder_button.config(state=tk.DISABLED,text='⏳ در حال تحلیل و تست...'); coder_log.delete('1.0',tk.END); coder_log.insert(tk.END,'شروع عامل برنامه‌نویس...\n')
        def worker():
            try:
                result=self_improve_code(topic,True)
                msg=f"✅ موفق شد.\n\nتابع: {result['function']}\nدلیل: {result['reason']}\nپشتیبان: {result['backup']}\n\nنسخه جدید با py_compile تست شد. برنامه را ببند و دوباره اجرا کن."
                brain_window.after(0,lambda: coder_log.insert(tk.END,msg+'\n')); brain_window.after(0,lambda: messagebox.showinfo('موفق','کد جدید تولید، تست و اعمال شد. برای بارگذاری نسخه جدید برنامه را دوباره اجرا کن.'))
            except Exception as e:
                brain_window.after(0,lambda: coder_log.insert(tk.END,f'❌ خطا: {e}\n')); brain_window.after(0,lambda: messagebox.showerror('خطا',str(e)))
            finally:
                brain_window.after(0,lambda: run_coder_button.config(state=tk.NORMAL,text='🧑‍💻 بنویس، تست کن و اعمال کن'))
        threading.Thread(target=worker,daemon=True).start()
    run_coder_button=tk.Button(coder_tab,text='🧑‍💻 بنویس، تست کن و اعمال کن',font=('Tahoma',11,'bold'),command=run_self_coder); run_coder_button.pack(pady=6)
    tk.Label(coder_tab,text='پشتیبان‌ها در پوشه ai_code_backups ذخیره می‌شوند و پاک‌سازی آزمایشی آن‌ها را حذف نمی‌کند.',font=('Tahoma',9),fg='gray').pack(pady=2)

    # =====================================================
    # تب ۴: پیشنهاد ارتقای برنامه (با تأیید مالک)
    # =====================================================

    suggest_tab = tk.Frame(notebook)
    notebook.add(suggest_tab, text="🛠️ پیشنهاد ارتقای برنامه")

    tk.Label(
        suggest_tab,
        text="AI می‌تواند برای بهتر شدن برنامه پیشنهاد بدهد؛ هیچ تغییری خودکار اعمال نمی‌شود — فقط با تأیید شما.",
        font=("Tahoma", 10), wraplength=900, justify="right"
    ).pack(pady=6)

    topic_frame = tk.Frame(suggest_tab)
    topic_frame.pack(fill=tk.X, padx=12, pady=4)
    tk.Label(topic_frame, text="موضوع (اختیاری):", font=("Tahoma", 10)).pack(side=tk.LEFT, padx=4)
    topic_entry = tk.Entry(topic_frame, width=60, font=("Tahoma", 10))
    topic_entry.pack(side=tk.LEFT, padx=4)

    suggest_list_frame = tk.Frame(suggest_tab)
    suggest_list_frame.pack(fill=tk.BOTH, expand=True, padx=12, pady=6)

    suggest_columns = ("id", "title", "status", "date")
    suggest_table = ttk.Treeview(suggest_list_frame, columns=suggest_columns, show="headings", height=8)
    suggest_table.heading("id", text="شناسه")
    suggest_table.heading("title", text="عنوان")
    suggest_table.heading("status", text="وضعیت")
    suggest_table.heading("date", text="تاریخ")
    suggest_table.column("id", width=50)
    suggest_table.column("title", width=420)
    suggest_table.column("status", width=100)
    suggest_table.column("date", width=140)
    suggest_table.pack(fill=tk.BOTH, expand=True)

    suggest_detail = scrolledtext.ScrolledText(suggest_tab, wrap=tk.WORD, font=("Tahoma", 10), height=10)
    suggest_detail.pack(fill=tk.BOTH, expand=True, padx=12, pady=6)

    status_labels = {"pending": "در انتظار", "approved": "تأیید شده", "rejected": "رد شده"}

    def refresh_suggestions():
        for item in suggest_table.get_children():
            suggest_table.delete(item)
        for sid, title, suggestion, status, created_at, reviewed_at in get_code_suggestions():
            suggest_table.insert("", tk.END, values=(sid, title, status_labels.get(status, status), created_at))

    def show_selected_suggestion(event=None):
        selection = suggest_table.selection()
        if not selection:
            return
        sid = suggest_table.item(selection[0])["values"][0]
        cursor.execute("SELECT suggestion FROM ai_code_suggestions WHERE id=?", (sid,))
        row = cursor.fetchone()
        suggest_detail.delete("1.0", tk.END)
        suggest_detail.insert(tk.END, row[0] if row else "")

    suggest_table.bind("<<TreeviewSelect>>", show_selected_suggestion)

    def run_request_suggestion():
        request_button.config(state=tk.DISABLED, text="⏳ در حال فکر کردن AI...")
        topic = topic_entry.get()

        def worker():
            try:
                request_code_suggestion(topic)
                brain_window.after(0, refresh_suggestions)
            except Exception as e:
                brain_window.after(0, lambda: messagebox.showerror("خطا", f"خطا در دریافت پیشنهاد: {e}"))
            finally:
                brain_window.after(0, lambda: request_button.config(state=tk.NORMAL, text="💡 درخواست پیشنهاد جدید از AI"))

        threading.Thread(target=worker, daemon=True).start()

    def approve_selected(approve):
        selection = suggest_table.selection()
        if not selection:
            messagebox.showwarning("توجه", "ابتدا یک پیشنهاد را انتخاب کنید.")
            return
        sid = suggest_table.item(selection[0])["values"][0]
        review_code_suggestion(sid, approve, note=get_active_employee())
        refresh_suggestions()

    suggest_buttons = tk.Frame(suggest_tab)
    suggest_buttons.pack(fill=tk.X, padx=12, pady=6)
    request_button = tk.Button(suggest_buttons, text="💡 درخواست پیشنهاد جدید از AI", font=("Tahoma", 10, "bold"), command=run_request_suggestion)
    request_button.pack(side=tk.LEFT, padx=5)
    tk.Button(suggest_buttons, text="✅ تأیید پیشنهاد", font=("Tahoma", 10), command=lambda: approve_selected(True)).pack(side=tk.LEFT, padx=5)
    tk.Button(suggest_buttons, text="❌ رد پیشنهاد", font=("Tahoma", 10), command=lambda: approve_selected(False)).pack(side=tk.LEFT, padx=5)
    tk.Button(suggest_buttons, text="🔄 بروزرسانی لیست", font=("Tahoma", 10), command=refresh_suggestions).pack(side=tk.LEFT, padx=5)

    refresh_suggestions()



# دکمه‌های مغز و حافظه — در ردیف بالا تا همیشه دیده شوند
brain_button = tk.Button(
    main_buttons,
    text="🧠 مغز مدیریتی",
    font=("Tahoma", 11, "bold"),
    command=open_ai_brain_window
)
brain_button.pack(side=tk.LEFT, padx=8)

clear_button = tk.Button(
    bottom_frame,
    text="🧠 پاک کردن حافظه",
    font=("Tahoma", 10),
    command=clear_chat
)
clear_button.pack(side=tk.LEFT, padx=8)



# =========================================================
# Enter
# =========================================================

entry.bind(
    "<Return>",
    lambda event: send_message()
)


# =========================================================
# شروع
# =========================================================

load_memory()

chat.insert(
    tk.END,
    "سلام! 🤖\n"
    "هوش مصنوعی، انبار و فروشگاه آماده هستند.\n\n"
    "📦 برای مدیریت کالا روی «باز کردن انبار» کلیک کن.\n"
    "🛒 برای فروش کالا روی «باز کردن فروشگاه» کلیک کن.\n"
    "💼 برای ثبت هزینه‌ها و دیدن سود و درآمد روی «حسابداری» کلیک کن.\n"
    "🤖 می‌توانی درباره موجودی و قیمت کالاها از من سؤال کنی.\n\n"
)


# =========================================================
# بستن برنامه
# =========================================================

def close_program():

    try:
        conn.commit()
        conn.close()

    except Exception:
        pass

    window.destroy()


window.protocol(
    "WM_DELETE_WINDOW",
    close_program
)




# =========================================================
# سیستم کارکنان و نقش ها
# =========================================================

def init_employee_roles():
    """ایجاد نقش های کارکنان فروشگاه"""
    try:
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS employees (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT,
                role TEXT,
                permissions TEXT
            )
        """)
        default_employees = [
            ("امید", "کارپرداز", "purchase"),
            ("احمد", "حسابدار", "accounting"),
            ("علی", "انباردار", "inventory"),
            ("موسی", "فروشنده", "sales")
        ]
        for emp in default_employees:
            cursor.execute("SELECT id FROM employees WHERE name=?", (emp[0],))
            if cursor.fetchone() is None:
                cursor.execute(
                    "INSERT INTO employees(name, role, permissions) VALUES(?,?,?)",
                    emp
                )
        conn.commit()
    except Exception:
        pass


# =========================================================
# اجرای برنامه
# =========================================================

def periodic_smart_monitor():
    try:
        run_smart_monitoring()
    except Exception as exc:
        print("Smart monitor error:", exc)
    try:
        window.after(120000, periodic_smart_monitor)  # هر ۲ دقیقه یک‌بار نظارت خودکار
    except Exception:
        pass

init_employee_roles()
try:
    seed_default_employee_tasks()
except Exception as exc:
    print("Task seed error:", exc)
window.after(3000, periodic_smart_monitor)
window.mainloop()