from decimal import Decimal

from sqlalchemy import text
from sqlalchemy.orm import Session

from app.catalog_products import CATALOG_CATEGORIES, CATALOG_PRODUCTS, DEMO_PUBLIC_IDS
from app.config import get_settings
from app.models import (
    BookingChannel,
    Client,
    CompanySetting,
    Document,
    Employee,
    Enquiry,
    EnquiryFollowup,
    EnquiryForm,
    EnquiryProduct,
    Event,
    EventProduct,
    Expense,
    ExpenseCategory,
    Feedback,
    FormField,
    FormFieldOption,
    FormSubmission,
    Invoice,
    InvoiceItem,
    InvoiceSetting,
    LeadSource,
    EmploymentType,
    Payment,
    Permission,
    Product,
    ProductCategory,
    Quotation,
    QuotationItem,
    QuotationSetting,
    Role,
    StaffAllocation,
    StaffPayment,
    SystemSetting,
    User,
)
from app.security import hash_password

PERMISSIONS = [
    ("dashboard.view", "View dashboard", "Dashboard"),
    ("enquiry.view", "View enquiries", "CRM"),
    ("enquiry.create", "Create enquiries", "CRM"),
    ("enquiry.edit", "Edit enquiries", "CRM"),
    ("enquiry.delete", "Delete enquiries", "CRM"),
    ("client.view", "View clients", "CRM"),
    ("client.create", "Create clients", "CRM"),
    ("client.edit", "Edit clients", "CRM"),
    ("client.delete", "Delete clients", "CRM"),
    ("followup.view", "View follow-ups", "CRM"),
    ("followup.create", "Create follow-ups", "CRM"),
    ("followup.edit", "Edit follow-ups", "CRM"),
    ("quotation.view", "View quotations", "CRM"),
    ("quotation.create", "Create quotations", "CRM"),
    ("quotation.edit", "Edit quotations", "CRM"),
    ("quotation.send", "Send quotations", "CRM"),
    ("event.view", "View events", "Events"),
    ("event.create", "Create events", "Events"),
    ("event.edit", "Edit events", "Events"),
    ("event.delete", "Delete events", "Events"),
    ("event.staff.allocate", "Allocate staff", "Events"),
    ("product.view", "View products", "Products"),
    ("product.create", "Create products", "Products"),
    ("product.edit", "Edit products", "Products"),
    ("product.delete", "Delete products", "Products"),
    ("gallery.view", "View website gallery", "Website"),
    ("gallery.create", "Add gallery images", "Website"),
    ("gallery.edit", "Edit gallery images", "Website"),
    ("gallery.delete", "Delete gallery images", "Website"),
    ("invoice.view", "View invoices", "Finance"),
    ("invoice.create", "Create invoices", "Finance"),
    ("invoice.edit", "Edit invoices", "Finance"),
    ("invoice.cancel", "Cancel invoices", "Finance"),
    ("payment.view", "View payments", "Finance"),
    ("payment.create", "Create payments", "Finance"),
    ("payment.edit", "Edit payments", "Finance"),
    ("payment.delete", "Delete payments", "Finance"),
    ("expense.view", "View expenses", "Finance"),
    ("expense.create", "Create expenses", "Finance"),
    ("expense.edit", "Edit expenses", "Finance"),
    ("expense.approve", "Approve expenses", "Finance"),
    ("staff.view", "View staff", "Staff"),
    ("staff.create", "Create staff", "Staff"),
    ("staff.edit", "Edit staff", "Staff"),
    ("staff.allocate", "Allocate staff", "Staff"),
    ("form.view", "View forms", "Forms"),
    ("form.create", "Create forms", "Forms"),
    ("form.edit", "Edit forms", "Forms"),
    ("report.sales", "Sales report", "Reports"),
    ("report.product", "Product report", "Reports"),
    ("report.employee", "Employee report", "Reports"),
    ("report.client", "Client report", "Reports"),
    ("report.finance", "Finance reports", "Reports"),
    ("user.view", "View users", "Admin"),
    ("user.create", "Create users", "Admin"),
    ("user.edit", "Edit users", "Admin"),
    ("user.delete", "Delete users", "Admin"),
    ("user.permissions", "Manage permissions", "Admin"),
    ("settings.view", "View settings", "Admin"),
    ("settings.edit", "Edit settings", "Admin"),
]

USER_PERMISSIONS = [
    "dashboard.view",
    "enquiry.view",
    "enquiry.create",
    "enquiry.edit",
    "client.view",
    "client.create",
    "client.edit",
    "followup.view",
    "followup.create",
    "followup.edit",
    "quotation.view",
    "quotation.create",
    "event.view",
    "product.view",
    "product.create",
    "product.edit",
    "product.delete",
    "gallery.view",
    "gallery.create",
    "gallery.edit",
    "gallery.delete",
    "staff.view",
]


def _perm_map(db: Session) -> dict[str, Permission]:
    existing = {p.key: p for p in db.query(Permission).all()}
    for key, name, module in PERMISSIONS:
        if key not in existing:
            perm = Permission(key=key, name=name, module=module)
            db.add(perm)
            db.flush()
            existing[key] = perm
    return existing


def _role(db: Session, name: str, description: str, keys: list[str], perms: dict[str, Permission]) -> Role:
    role = db.query(Role).filter(Role.name == name).first()
    if role is None:
        role = Role(name=name, description=description, is_system=True)
        db.add(role)
        db.flush()
    role.permissions = [perms[key] for key in keys if key in perms]
    return role


def _user(db: Session, name: str, email: str, password: str, role: Role, phone: str) -> User:
    user = db.query(User).filter(User.email == email).first()
    if user is None:
        user = User(name=name, email=email, phone=phone, password_hash=hash_password(password), is_active=True)
        db.add(user)
        db.flush()
    if role not in user.roles:
        user.roles.append(role)
    return user


def seed_all(db: Session) -> None:
    settings = get_settings()
    perms = _perm_map(db)
    all_keys = list(perms.keys())
    admin_keys = [k for k in all_keys if k not in {"user.permissions", "user.delete"}]
    super_role = _role(db, "Super Admin", "Full access", all_keys, perms)
    admin_role = _role(db, "Admin", "Operational admin", admin_keys, perms)
    user_role = _role(db, "User", "CRM and assigned modules", USER_PERMISSIONS, perms)

    _user(db, "SelfiePetti Super Admin", settings.seed_super_admin_email, settings.seed_super_admin_password, super_role, "9000000001")
    _user(db, "Operations Admin", settings.seed_admin_email, settings.seed_admin_password, admin_role, "9000000002")
    _user(db, "CRM Executive", settings.seed_user_email, settings.seed_user_password, user_role, "9000000003")

    if db.query(CompanySetting).first() is None:
        db.add(
            CompanySetting(
                company_name="SELFIE PETTI",
                phone="9043717464",
                email="selfiepetti@gmail.com",
                website="www.selfiepetti.com",
                address="12 Th South Street, Sakthi Complex Thiyagaraja Nagar\nTIRUNELVELI, TAMIL NADU 627007",
                gstin="33AAACL0140P5ZM",
            )
        )
    if db.query(InvoiceSetting).first() is None:
        db.add(InvoiceSetting(prefix="INV", next_number=1, default_due_days=7, terms="Balance due before event day."))
    if db.query(QuotationSetting).first() is None:
        db.add(QuotationSetting(prefix="QUO", next_number=1))
    if db.query(SystemSetting).first() is None:
        db.add(SystemSetting())

    for name in ["Travel", "Fuel", "Food", "Accommodation", "Staff Salary", "Equipment", "Maintenance", "Other"]:
        if db.query(ExpenseCategory).filter(ExpenseCategory.name == name).first() is None:
            db.add(ExpenseCategory(name=name))

    for name in ["Instagram", "WhatsApp", "Referral", "Walk-in", "Google", "Wedding Planner"]:
        if db.query(LeadSource).filter(LeadSource.name == name).first() is None:
            db.add(LeadSource(name=name))

    for name in ["Phone", "WhatsApp", "Instagram", "Website", "Walk-in", "Email"]:
        if db.query(BookingChannel).filter(BookingChannel.name == name).first() is None:
            db.add(BookingChannel(name=name))

    for name in ["Regular", "Non-Regular", "Weekend only", "As contacted"]:
        if db.query(EmploymentType).filter(EmploymentType.name == name).first() is None:
            db.add(EmploymentType(name=name))

    # Replace legacy seeded types when unused.
    for old_name, new_name in [
        ("Permanent", "Regular"),
        ("Contract", "Non-Regular"),
        ("Freelance", "As contacted"),
    ]:
        old = db.query(EmploymentType).filter(EmploymentType.name == old_name).first()
        if old is None:
            continue
        new = db.query(EmploymentType).filter(EmploymentType.name == new_name).first()
        if new is None:
            old.name = new_name
            continue
        used = db.query(Employee).filter(Employee.employment_type == old_name).count()
        if used == 0:
            db.delete(old)
        else:
            db.query(Employee).filter(Employee.employment_type == old_name).update(
                {Employee.employment_type: new_name}
            )
            db.delete(old)

    # Only seed the product catalog on a fresh database. Never wipe existing data on startup.
    if db.query(Product).count() == 0:
        load_catalog_products(db)

    db.commit()


def has_demo_data(db: Session) -> bool:
    checks = [
        db.query(Product.public_id).filter(Product.public_id.in_(DEMO_PUBLIC_IDS)).first(),
        db.query(Client.public_id).filter(Client.public_id.in_(DEMO_PUBLIC_IDS)).first(),
        db.query(Enquiry.public_id).filter(Enquiry.public_id.in_(DEMO_PUBLIC_IDS)).first(),
        db.query(Event.public_id).filter(Event.public_id.in_(DEMO_PUBLIC_IDS)).first(),
        db.query(Employee.public_id).filter(Employee.public_id.in_(DEMO_PUBLIC_IDS)).first(),
        db.query(Invoice.public_id).filter(Invoice.public_id.in_(DEMO_PUBLIC_IDS)).first(),
    ]
    return any(checks)


def wipe_operational_data(db: Session) -> dict[str, int]:
    dialect = db.get_bind().dialect.name
    if dialect == "mysql":
        db.execute(text("SET FOREIGN_KEY_CHECKS=0"))
    counts = {}
    for model in (
        StaffPayment,
        StaffAllocation,
        EventProduct,
        Payment,
        InvoiceItem,
        Invoice,
        Expense,
        Feedback,
        Document,
        QuotationItem,
        Quotation,
        FormSubmission,
        FormFieldOption,
        FormField,
        EnquiryForm,
        EnquiryFollowup,
        EnquiryProduct,
        Enquiry,
        Event,
        Client,
        Employee,
        Product,
        ProductCategory,
    ):
        counts[model.__tablename__] = db.query(model).delete()
    invoice_settings = db.query(InvoiceSetting).first()
    if invoice_settings is not None:
        invoice_settings.next_number = 1
    if dialect == "mysql":
        db.execute(text("SET FOREIGN_KEY_CHECKS=1"))
    db.flush()
    return counts


def load_catalog_products(db: Session) -> int:
    categories: dict[str, ProductCategory] = {}
    for name in CATALOG_CATEGORIES:
        row = db.query(ProductCategory).filter(ProductCategory.name == name).first()
        if row is None:
            row = ProductCategory(name=name, is_active=True)
            db.add(row)
            db.flush()
        categories[name] = row

    created = 0
    for public_id, name, category_name, price in CATALOG_PRODUCTS:
        row = db.query(Product).filter(Product.public_id == public_id).first()
        if row is None:
            db.add(
                Product(
                    public_id=public_id,
                    name=name,
                    category_id=categories[category_name].id,
                    description=None,
                    base_price=price,
                    cost=Decimal("0"),
                    is_active=True,
                )
            )
            created += 1
        else:
            row.name = name
            row.category_id = categories[category_name].id
            row.base_price = price
            row.is_active = True
    db.flush()
    return created
