import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

from database import engine, Base
from middleware.license_check import LicenseCheckMiddleware
from services.cloud_sync import start_cloud_sync

# Import all models so SQLAlchemy can create their tables
import models.user          # noqa: F401 — also registers WaiterZone
import models.table         # noqa: F401
import models.printer       # noqa: F401
import models.product       # noqa: F401
import models.order         # noqa: F401 — also registers OrderAuditLog, OrderDiscount
import models.business_day  # noqa: F401
import models.shift         # noqa: F401 — registers WaiterShift, ShiftBreak
import models.settings      # noqa: F401
import models.flag          # noqa: F401 — registers TableFlagDef, TableFlagAssignment
import models.message       # noqa: F401 — registers StaffMessage, StaffMessageAck, QuickMessageTemplate

from routers import auth, tables, products, orders, waiters, reports, system
from routers import business_day as business_day_router
from routers import shifts as shifts_router
from routers import settings as settings_router
from routers import flags as flags_router
from routers import messages as messages_router
from routers import sse as sse_router


def _run_migrations():
    """Apply additive schema changes that create_all won't handle.
    Each migration gets its own connection so a no-op (column already exists)
    doesn't leave a dirty transaction that blocks subsequent migrations."""
    from sqlalchemy import text

    migrations = [
        "ALTER TABLE product_ingredients ADD COLUMN extra_cost REAL NOT NULL DEFAULT 0.0",
        "ALTER TABLE products ADD COLUMN image_url VARCHAR",
        "ALTER TABLE tables ADD COLUMN group_id INTEGER REFERENCES table_groups(id)",
        "ALTER TABLE table_groups ADD COLUMN prefix VARCHAR",
        "ALTER TABLE table_groups ADD COLUMN color VARCHAR",
        "ALTER TABLE products ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_preference_sets ADD COLUMN default_choice_id INTEGER",
        "ALTER TABLE product_preference_choices ADD COLUMN sub_choices TEXT",
        "ALTER TABLE product_preference_choices ADD COLUMN disables_subset INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_preference_sets ADD COLUMN shared_subset TEXT",
        "ALTER TABLE product_options ADD COLUMN sub_choices TEXT",
        # Zone-based access control
        """CREATE TABLE IF NOT EXISTS waiter_zones (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            waiter_id INTEGER NOT NULL REFERENCES users(id),
            group_id INTEGER REFERENCES table_groups(id),
            assigned_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        # Payment tracking on items
        "ALTER TABLE order_items ADD COLUMN paid_by INTEGER REFERENCES users(id)",
        "ALTER TABLE order_items ADD COLUMN paid_at DATETIME",
        "ALTER TABLE order_items ADD COLUMN payment_method VARCHAR",
        # Full audit log
        """CREATE TABLE IF NOT EXISTS order_audit_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            order_id INTEGER NOT NULL REFERENCES orders(id),
            event_type VARCHAR NOT NULL,
            waiter_id INTEGER REFERENCES users(id),
            item_ids TEXT,
            amount REAL,
            payment_method VARCHAR,
            note TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        # Waiter profile fields
        "ALTER TABLE users ADD COLUMN full_name VARCHAR",
        "ALTER TABLE users ADD COLUMN nickname VARCHAR",
        "ALTER TABLE users ADD COLUMN mobile_phone VARCHAR",
        "ALTER TABLE users ADD COLUMN avatar_url VARCHAR",
        # Quick options (flat, allow_multiple)
        """CREATE TABLE IF NOT EXISTS product_quick_options (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            product_id INTEGER NOT NULL REFERENCES products(id),
            name VARCHAR NOT NULL,
            price REAL NOT NULL DEFAULT 0.0,
            allow_multiple INTEGER NOT NULL DEFAULT 0,
            sort_order INTEGER NOT NULL DEFAULT 0
        )""",
        # allow_multiple flag on extras (product_options)
        "ALTER TABLE product_options ADD COLUMN allow_multiple INTEGER NOT NULL DEFAULT 0",
        # Discounts table (future-proofed, schema ready now)
        """CREATE TABLE IF NOT EXISTS order_discounts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            order_id INTEGER NOT NULL REFERENCES orders(id),
            item_id INTEGER REFERENCES order_items(id),
            discount_type VARCHAR NOT NULL,
            discount_value REAL NOT NULL,
            applied_by INTEGER NOT NULL REFERENCES users(id),
            applied_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            reason TEXT
        )""",
        # Business day scoping on orders
        "ALTER TABLE orders ADD COLUMN business_day_id INTEGER REFERENCES business_days(id)",
        # Shift attribution on paid items
        "ALTER TABLE order_items ADD COLUMN paid_in_shift_id INTEGER REFERENCES waiter_shifts(id)",
        # Seed default POS settings (INSERT OR IGNORE = no-op if already exists)
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('shifts.waiter_self_start', 'true', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('shifts.waiter_self_end', 'true', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('business_day.force_close_allowed', 'true', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('flags.display_mode', 'both', CURRENT_TIMESTAMP)",
        # Table flags
        """CREATE TABLE IF NOT EXISTS table_flag_defs (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name VARCHAR NOT NULL,
            emoji VARCHAR,
            color VARCHAR DEFAULT '#6b7280',
            text_color VARCHAR DEFAULT NULL,
            sort_order INTEGER NOT NULL DEFAULT 0,
            is_active INTEGER NOT NULL DEFAULT 1,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        # Migration: add text_color if upgrading from older schema
        "ALTER TABLE table_flag_defs ADD COLUMN text_color VARCHAR DEFAULT NULL",
        """CREATE TABLE IF NOT EXISTS table_flag_assignments (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            table_id INTEGER NOT NULL REFERENCES tables(id),
            flag_id INTEGER NOT NULL REFERENCES table_flag_defs(id),
            assigned_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            assigned_by INTEGER REFERENCES users(id)
        )""",
        # Staff messaging
        """CREATE TABLE IF NOT EXISTS quick_message_templates (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            body VARCHAR NOT NULL,
            sort_order INTEGER NOT NULL DEFAULT 0,
            is_active INTEGER NOT NULL DEFAULT 1,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        """CREATE TABLE IF NOT EXISTS staff_messages (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            sender_id INTEGER NOT NULL REFERENCES users(id),
            body TEXT NOT NULL,
            target_waiter_ids TEXT NOT NULL DEFAULT '[]',
            table_ids TEXT NOT NULL DEFAULT '[]',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        """CREATE TABLE IF NOT EXISTS staff_message_acks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            message_id INTEGER NOT NULL REFERENCES staff_messages(id),
            waiter_id INTEGER NOT NULL REFERENCES users(id),
            acked_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )""",
        # Seed default flag definitions
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (1, 'Χρειάζεται καθάρισμα', '🧹', '#ef4444', 1)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (2, 'Χρειάζεται Βοήθεια', '🆘', '#f97316', 2)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (3, 'Χρειάζεται Σερβιτόρο', '🔔', '#eab308', 3)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (4, 'Περιμένει να πληρώσει', '💳', '#3b82f6', 4)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (5, 'VIP', '⭐', '#8b5cf6', 5)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (6, 'Ευγενικός Πελάτης', '😊', '#22c55e', 6)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (7, 'Αγενής Πελάτης', '😤', '#dc2626', 7)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (8, 'Αλλεργίες', '⚠️', '#f59e0b', 8)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (9, 'Παιδιά στο τραπέζι', '👶', '#06b6d4', 9)",
        "INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (10, 'Επέτειος / Γενέθλια', '🎂', '#ec4899', 10)",
        # Seed default quick message templates
        "INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (1, 'Σε χρειάζομαι τώρα', 1)",
        "INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (2, 'Πάρε διάλειμμα', 2)",
        "INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (3, 'Ετοιμάσου για κλείσιμο', 3)",
        "INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (4, 'Ήρθε νέος πελάτης', 4)",
        "INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (5, 'Ο πελάτης περιμένει να πληρώσει', 5)",
        # Product lifecycle status (active / archived)
        "ALTER TABLE products ADD COLUMN lifecycle_status VARCHAR NOT NULL DEFAULT 'active'",
        # Favorite flags + ordering on all product sub-item types
        "ALTER TABLE product_quick_options ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_quick_options ADD COLUMN favorite_sort_order INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_options ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_options ADD COLUMN favorite_sort_order INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_ingredients ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_ingredients ADD COLUMN favorite_sort_order INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_preference_sets ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0",
        "ALTER TABLE product_preference_sets ADD COLUMN favorite_sort_order INTEGER NOT NULL DEFAULT 0",
        # Sub-category support
        "ALTER TABLE categories ADD COLUMN parent_id INTEGER REFERENCES categories(id)",
        "ALTER TABLE categories ADD COLUMN general_sort_order INTEGER NOT NULL DEFAULT 0",
        # Auto-expand flag for sub-categories on the PWA accordion
        "ALTER TABLE categories ADD COLUMN auto_expanded INTEGER NOT NULL DEFAULT 0",
        # Printer protocol field
        "ALTER TABLE printers ADD COLUMN protocol VARCHAR NOT NULL DEFAULT 'escpos_tcp'",
        # Compact (half-width) display flag for quick options
        "ALTER TABLE product_quick_options ADD COLUMN is_compact INTEGER NOT NULL DEFAULT 0",
        # Print layout + per-type font settings
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.ticket_mode', 'detailed', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_order_number', '48:1:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_meta', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_item_name', '16:1:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_quick', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_pref', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_extra', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_ingredient', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_item_note', '0:0:0', CURRENT_TIMESTAMP)",
        "INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_order_note', '0:1:0', CURRENT_TIMESTAMP)",
        # Offline/emergency payment tracking
        "ALTER TABLE order_audit_log ADD COLUMN offline_uuid VARCHAR",
        "ALTER TABLE order_audit_log ADD COLUMN offline_at VARCHAR",
        "ALTER TABLE order_audit_log ADD COLUMN is_duplicate INTEGER NOT NULL DEFAULT 0",
    ]
    for sql in migrations:
        try:
            with engine.connect() as conn:
                conn.execute(text(sql))
                conn.commit()
        except Exception:
            pass


@asynccontextmanager
async def lifespan(app: FastAPI):
    import asyncio
    from services.sse_bus import init_loop
    init_loop(asyncio.get_running_loop())
    Base.metadata.create_all(bind=engine)
    _run_migrations()
    sync_task = await start_cloud_sync()
    yield
    sync_task.cancel()


app = FastAPI(title="POS Local Backend", lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(LicenseCheckMiddleware)

# Serve product images as static files
IMAGE_DIR = "/app/data/product_images"
os.makedirs(IMAGE_DIR, exist_ok=True)
app.mount("/static/product_images", StaticFiles(directory=IMAGE_DIR), name="product_images")

# Serve waiter avatars as static files
AVATAR_DIR = "/app/data/avatars"
os.makedirs(AVATAR_DIR, exist_ok=True)
app.mount("/static/avatars", StaticFiles(directory=AVATAR_DIR), name="avatars")

app.include_router(auth.router,                  prefix="/api/auth",         tags=["auth"])
app.include_router(tables.router,                prefix="/api/tables",       tags=["tables"])
app.include_router(products.router,              prefix="/api/products",     tags=["products"])
app.include_router(orders.router,                prefix="/api/orders",       tags=["orders"])
app.include_router(waiters.router,               prefix="/api/waiters",      tags=["waiters"])
app.include_router(reports.router,               prefix="/api/reports",      tags=["reports"])
app.include_router(system.router,                prefix="/api/system",       tags=["system"])
app.include_router(business_day_router.router,   prefix="/api/business-day", tags=["business-day"])
app.include_router(shifts_router.router,         prefix="/api/shifts",       tags=["shifts"])
app.include_router(settings_router.router,       prefix="/api/settings",     tags=["settings"])
app.include_router(flags_router.router,          prefix="/api/flags",        tags=["flags"])
app.include_router(messages_router.router,       prefix="/api/messages",     tags=["messages"])
app.include_router(sse_router.router,            prefix="/api/sse",          tags=["sse"])
