from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from datetime import datetime, timezone

from database import get_db
from models.settings import PosSettings
from schemas.settings import UpdateSettingRequest
from routers.deps import get_current_user, require_settings_manager
from models.user import User

router = APIRouter()

VALID_SETTINGS = {
    # Security / auth
    "security.login_method":       "How managers authenticate on first login: 'password' | 'pin' | 'none'",
    "security.autofill_username":  "Auto-fill username when only one manager exists: 'true' | 'false'",
    "security.auto_lock":          "Lock screen after inactivity: 'true' | 'false'",
    "security.auto_lock_seconds":  "Seconds of inactivity before locking (0 = disabled)",
    "security.auto_logout":        "Log out after inactivity: 'true' | 'false'",
    "security.auto_logout_seconds":"Seconds of inactivity before logging out (0 = disabled)",
    "shifts.waiter_self_start": "Allow waiters to start their own shifts without manager action",
    "shifts.waiter_self_end": "Allow waiters to end their own shifts without manager action",
    "shifts.hide_revenue_from_waiters": "Hide ΕΙΣΠΡΑΞΗ and ΠΑΡΑΔ. ΠΟΣΟ stats from waiters in Shift Overview: 'true' | 'false'",
    "business_day.force_close_allowed": "Allow force-closing business day with open tables",
    "system.timezone": "IANA timezone name used by the backend container (e.g. Europe/Athens). Requires container restart to take effect.",
    "ui.table_colours": "JSON blob of table card colour scheme (light + dark modes) for the Waiter PWA.",
    "dev.spoof_printing": "When enabled, all print jobs are silently dropped. Devices behave as if printing succeeded.",
    # Print layout
    "print.ticket_mode":       "Kitchen ticket layout mode: 'detailed' or 'compact'",
    "print.divider_style":     "Divider character used between sections: dash, equals, star, or empty",
    "print.dot_style":         "Dot-leader style for item lines: STYLE:SIZE:BOLD where STYLE is dot_space|dot|dash_space|underscore, SIZE is ESC ! base byte (0/16/32/48), BOLD 0|1",
    # Print font settings — values are "SIZE:BOLD:CAPS" where SIZE is ESC ! base byte (0/16/32/48), BOLD 0|1, CAPS 0|1
    "print.font_order_number": "Font for order number header: SIZE:BOLD:CAPS",
    "print.font_meta":         "Font for table/waiter/time header block: SIZE:BOLD:CAPS",
    "print.font_item_name":    "Font for item name lines: SIZE:BOLD:CAPS",
    "print.font_quick":        "Font for quick option lines (* marker): SIZE:BOLD:CAPS",
    "print.font_pref":         "Font for preference choice lines (> marker): SIZE:BOLD:CAPS",
    "print.font_extra":        "Font for extra/option lines (+ marker): SIZE:BOLD:CAPS",
    "print.font_ingredient":   "Font for removed ingredient lines (- marker): SIZE:BOLD:CAPS",
    "print.font_item_note":    "Font for per-item note lines: SIZE:BOLD:CAPS",
    "print.font_order_note":   "Font for order-level notes: SIZE:BOLD:CAPS",
    # Beep settings
    "print.beep_on_ticket":    "Play beep when a kitchen ticket prints: 'true' | 'false'",
    "print.beep_pattern":      "Beep pattern: 'single' | 'double' | 'triple' | 'long' | 'custom:n1:n2:n3'",
    # Phase 2 — cancellations
    "orders.waiter_cancellations_allowed": "Allow waiters with per-account permission to cancel sent orders: 'true' | 'false'",
    "orders.waiter_price_adjust_allowed": "Allow waiters to adjust item prices (before or after ordering): 'true' | 'false'",
    # Payment options
    "payments.card_enabled": "Allow waiters to record card payments (in addition to cash): 'true' | 'false'",
    "payments.waiter_revert_allowed": "Allow waiters to revert individual paid items back to unpaid: 'true' | 'false'",
    # Tables & orders behaviour
    "orders.auto_close_on_full_payment": "Automatically close the table order when all items have been paid: 'true' | 'false'",
    "orders.bypass_kds_serve": "Skip KDS pending/serve flow — new orders and items are immediately marked as served: 'true' | 'false'",
    # Courses
    "orders.courses_enabled": "Enable per-item course assignment when ordering: 'true' | 'false'",
    "orders.courses": "JSON array of course objects [{id, name, color}] defining available courses",
    # Quick notes
    "orders.quick_notes": "JSON array of quick-note strings shown in the waiter note tab",
    # Fiscal printer (ΦΗΜ)
    "fiscal.enabled":      "Master switch for fiscal printing: 'true' | 'false'",
    "fiscal.type":         "Fiscal driver type: 'txt_file' (dTEC100extra) — more types coming",
    "fiscal.out_folder":   "Path the backend writes fiscal command files TO (input for the fiscal driver)",
    "fiscal.in_folder":    "Path the backend reads fiscal reply files FROM (output of the fiscal driver)",
    "fiscal.clerk_id":     "Clerk ID sent in CR/CD commands (integer string, e.g. '2')",
    "fiscal.eftpos_id":    "EFTPOS terminal ID sent in CD commands (integer string, e.g. '1')",
    "fiscal.end_message":  "JSON array of up to 5 strings printed at end of receipt via FM commands",
    "fiscal.vat_groups":   "JSON array of VAT group definitions: [{machine_id: int, friendly_name: str}]",
}

DEFAULTS = {
    "security.login_method":        "password",
    "security.autofill_username":   "true",
    "security.auto_lock":           "false",
    "security.auto_lock_seconds":   "300",
    "security.auto_logout":         "false",
    "security.auto_logout_seconds": "1800",
    "shifts.waiter_self_start": "true",
    "shifts.waiter_self_end": "true",
    "shifts.hide_revenue_from_waiters": "false",
    "business_day.force_close_allowed": "true",
    "system.timezone": "Europe/Athens",
    "ui.table_colours": '{"light":{"free":{"cardBg":"#dde5ef","badgeBg":"rgba(255,255,255,0.92)","nameText":"#3d5270","badgeText":"#3d5270"},"mine":{"cardBg":"#e8610a","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#e8610a"},"open":{"cardBg":"#FF8F60","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#FF8F60"},"partially_paid":{"cardBg":"#FFDC67","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#d4a800"},"paid":{"cardBg":"#81D264","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#81D264"},"kds_ready":{"cardBg":"#22c55e","cardBg2":"#ffffff","badgeBg":"rgba(255,255,255,0.92)","badgeBg2":"rgba(255,255,255,0.92)","nameText":"#ffffff","nameText2":"#15803d","badgeText":"#15803d","badgeText2":"#22c55e","flash":true}},"dark":{"free":{"cardBg":"#243044","badgeBg":"rgba(255,255,255,0.92)","nameText":"#94b8d4","badgeText":"#94b8d4"},"mine":{"cardBg":"#e8610a","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#e8610a"},"open":{"cardBg":"#FF8F60","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#FF8F60"},"partially_paid":{"cardBg":"#FFDC67","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#d4a800"},"paid":{"cardBg":"#81D264","badgeBg":"rgba(255,255,255,0.92)","nameText":"#ffffff","badgeText":"#81D264"},"kds_ready":{"cardBg":"#16a34a","cardBg2":"#ffffff","badgeBg":"rgba(255,255,255,0.92)","badgeBg2":"rgba(255,255,255,0.92)","nameText":"#ffffff","nameText2":"#bbf7d0","badgeText":"#bbf7d0","badgeText2":"#16a34a","flash":true}}}',
    "dev.spoof_printing": "false",
    "print.ticket_mode":       "detailed",
    "print.divider_style":     "dash",
    "print.dot_style":         "dot_space:0:0",
    "print.font_order_number": "48:1:0",
    "print.font_meta":         "0:0:0",
    "print.font_item_name":    "16:1:0",
    "print.font_quick":        "0:0:0",
    "print.font_pref":         "0:0:0",
    "print.font_extra":        "0:0:0",
    "print.font_ingredient":   "0:0:0",
    "print.font_item_note":    "0:0:0",
    "print.font_order_note":   "0:1:0",
    "print.beep_on_ticket":    "true",
    "print.beep_pattern":      "double",
    "payments.card_enabled": "false",
    "payments.waiter_revert_allowed": "false",
    "orders.auto_close_on_full_payment": "false",
    "orders.bypass_kds_serve": "false",
    "orders.waiter_price_adjust_allowed": "false",
    "orders.courses_enabled": "false",
    "orders.courses": "[]",
    "orders.quick_notes": '["Χωρίς αλάτι","Βγάλτε γρήγορα","Αλλεργία!","Κόψτε σε μικρά κομμάτια","Έξτρα χαρτοπετσέτες"]',
    # Fiscal printer (ΦΗΜ)
    "fiscal.enabled":     "false",
    "fiscal.type":        "txt_file",
    "fiscal.out_folder":  "",
    "fiscal.in_folder":   "",
    "fiscal.clerk_id":    "2",
    "fiscal.eftpos_id":   "1",
    "fiscal.end_message": "[]",
    "fiscal.vat_groups":  "[]",
}


@router.get("/")
def get_all_settings(
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    stored = {s.key: s.value for s in db.query(PosSettings).all()}
    result = {}
    for key, description in VALID_SETTINGS.items():
        result[key] = {
            "value": stored.get(key, DEFAULTS.get(key, "true")),
            "description": description,
        }
    return result


@router.put("/{key}")
def update_setting(
    key: str,
    body: UpdateSettingRequest,
    db: Session = Depends(get_db),
    user: User = Depends(require_settings_manager),
):
    if key not in VALID_SETTINGS:
        raise HTTPException(status_code=400, detail=f"Unknown setting key: {key}")

    setting = db.query(PosSettings).filter(PosSettings.key == key).first()
    if setting:
        setting.value = body.value
        setting.updated_at = datetime.now(timezone.utc)
        setting.updated_by_id = user.id
    else:
        setting = PosSettings(key=key, value=body.value, updated_by_id=user.id)
        db.add(setting)

    db.commit()
    db.refresh(setting)
    return {"key": setting.key, "value": setting.value}
