import sys
from typing import Dict, List
from sqlalchemy import and_

from app.core.database import SessionLocal
from app.models.accounting_dimensions import AccountingDimension, AccountingDimensionValue, DimensionType, DimensionScope
from app.models.accounting_code_dimensions import AccountingCodeDimensionRequirement
from app.models.accounting import AccountingCode

# Seed blueprint
DIMENSIONS: List[Dict] = [
    {"code": "BRANCH", "name": "Branch", "dimension_type": DimensionType.GEOGRAPHICAL, "scope": DimensionScope.GLOBAL, "is_required": True, "values": ["HQ", "BR1", "BR2"]},
    {"code": "DEPT", "name": "Department", "dimension_type": DimensionType.FUNCTIONAL, "scope": DimensionScope.GLOBAL, "is_required": True, "values": ["SALES", "OPS", "FIN", "MKT"]},
    {"code": "CC", "name": "Cost Center", "dimension_type": DimensionType.FUNCTIONAL, "scope": DimensionScope.GLOBAL, "is_required": True, "values": ["CC-RETAIL", "CC-WHOLE", "CC-SERVICE"]},
    {"code": "PROJ", "name": "Project", "dimension_type": DimensionType.PROJECT, "scope": DimensionScope.GLOBAL, "is_required": False, "values": ["PROJ-ALPHA", "PROJ-BETA"]},
    {"code": "PRODLINE", "name": "Product Line", "dimension_type": DimensionType.PRODUCT, "scope": DimensionScope.GLOBAL, "is_required": False, "values": ["FOOD", "BEV", "NONFOOD"]},
    {"code": "CUSTSEG", "name": "Customer Segment", "dimension_type": DimensionType.CUSTOMER, "scope": DimensionScope.GLOBAL, "is_required": False, "values": ["RETAIL", "B2B", "ONLINE"]},
    {"code": "WH", "name": "Warehouse", "dimension_type": DimensionType.GEOGRAPHICAL, "scope": DimensionScope.GLOBAL, "is_required": True, "values": ["MAIN-WH", "SEC-WH"]},
    {"code": "REGION", "name": "Region", "dimension_type": DimensionType.GEOGRAPHICAL, "scope": DimensionScope.GLOBAL, "is_required": False, "values": ["NORTH", "SOUTH", "EAST", "WEST"]},
]

# Defaults to apply per account type; maps account_type string -> list of (dimension_code, default_value_code)
# IFRS-compliant dimension assignments:
# - BRANCH: All accounts need branch tracking (IAS 24 - Related Party Disclosures)
# - DEPT/CC: Expense tracking by department/cost center (IAS 1 - Presentation)
# - PRODLINE: Product line tracking for revenue (IFRS 15 - Revenue disaggregation)
# - CUSTSEG: Customer segment for revenue (IFRS 8/15 - Segment & revenue disaggregation)
# - REGION: Geographic tracking for assets/liabilities (IFRS 8 - Geographic segments)
# - WH: Warehouse tracking for inventory assets (IAS 2 - Inventories)
# - PROJ: Project tracking for expenses (IAS 38 - Intangibles, capitalized dev costs)
ACCOUNT_DEFAULTS = {
    "Revenue": [
        ("BRANCH", "HQ"), ("DEPT", "SALES"), ("CC", "CC-RETAIL"),
        ("PRODLINE", "FOOD"), ("CUSTSEG", "RETAIL")  # IFRS 15 requires customer segment disaggregation
    ],
    "Expense": [
        ("BRANCH", "HQ"), ("DEPT", "OPS"), ("CC", "CC-SERVICE"), ("PROJ", "PROJ-ALPHA")
    ],
    "Asset": [
        ("BRANCH", "HQ"), ("WH", "MAIN-WH"), ("REGION", "NORTH")
    ],
    "Liability": [
        ("BRANCH", "HQ"), ("REGION", "NORTH")
    ],
    "Equity": [
        ("BRANCH", "HQ")
    ],
}


def get_or_create_dimension(db, code: str, name: str, dimension_type: DimensionType, scope: DimensionScope, is_required: bool):
    dim = db.query(AccountingDimension).filter(AccountingDimension.code == code).first()
    if dim:
        dim.name = name
        dim.dimension_type = dimension_type
        dim.scope = scope
        dim.is_required = is_required
        db.add(dim)
        db.flush()
        return dim
    dim = AccountingDimension(
        code=code,
        name=name,
        dimension_type=dimension_type.value,
        scope=scope.value,
        is_required=is_required,
        allow_multiple_values=False,
        supports_hierarchy=False,
        max_hierarchy_levels=1,
    )
    db.add(dim)
    db.flush()
    return dim


def get_or_create_value(db, dim: AccountingDimension, code: str):
    val = db.query(AccountingDimensionValue).filter(and_(AccountingDimensionValue.dimension_id == dim.id, AccountingDimensionValue.code == code)).first()
    if val:
        return val
    val = AccountingDimensionValue(
        dimension_id=dim.id,
        code=code,
        name=code.replace('-', ' ').title(),
        description=None,
        parent_value_id=None,
        is_active=True,
        display_order=0,
    )
    db.add(val)
    db.flush()
    return val


def set_requirement(db, account_id: str, dim_id: str, default_val_id: str, is_required: bool):
    req = db.query(AccountingCodeDimensionRequirement).filter(
        and_(
            AccountingCodeDimensionRequirement.accounting_code_id == account_id,
            AccountingCodeDimensionRequirement.dimension_id == dim_id,
        )
    ).first()
    if req:
        req.default_dimension_value_id = default_val_id
        req.is_required = is_required or req.is_required
        db.add(req)
        return
    req = AccountingCodeDimensionRequirement(
        accounting_code_id=account_id,
        dimension_id=dim_id,
        is_required=is_required,
        default_dimension_value_id=default_val_id,
        priority=1,
        description="Seeded default",
    )
    db.add(req)


def main():
    db = SessionLocal()
    try:
        code_to_dim: Dict[str, AccountingDimension] = {}
        value_lookup: Dict[str, Dict[str, AccountingDimensionValue]] = {}

        # Seed dimensions and values
        for d in DIMENSIONS:
            dim = get_or_create_dimension(
                db,
                code=d["code"],
                name=d["name"],
                dimension_type=d["dimension_type"],
                scope=d["scope"],
                is_required=d.get("is_required", False),
            )
            code_to_dim[d["code"]] = dim
            value_lookup[d["code"]] = {}
            for val_code in d.get("values", []):
                val = get_or_create_value(db, dim, val_code)
                value_lookup[d["code"]][val_code] = val

        db.commit()

        # Apply defaults to accounts by account_type
        accounts = db.query(AccountingCode).all()
        for acct in accounts:
            defaults = ACCOUNT_DEFAULTS.get(acct.account_type)
            if not defaults:
                continue
            for dim_code, val_code in defaults:
                dim = code_to_dim.get(dim_code)
                if not dim:
                    continue
                val = value_lookup.get(dim_code, {}).get(val_code)
                if not val:
                    continue
                set_requirement(db, acct.id, dim.id, val.id, is_required=True)
        db.commit()

        print("Seed complete: dimensions, values, and default requirements applied.")
    except Exception as e:
        db.rollback()
        print(f"Seed failed: {e}")
        sys.exit(1)
    finally:
        db.close()


if __name__ == "__main__":
    main()
