from __future__ import annotations import uuid from datetime import datetime, timezone from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db.models.category import Category SYSTEM_CATEGORIES = [ # Income {"name": "Salary", "type": "income", "icon": "briefcase", "color": "#22c55e"}, {"name": "Freelance", "type": "income", "icon": "laptop", "color": "#22c55e"}, {"name": "Investment Income", "type": "income", "icon": "trending-up", "color": "#22c55e"}, {"name": "Rental Income", "type": "income", "icon": "home", "color": "#22c55e"}, {"name": "Benefits", "type": "income", "icon": "shield", "color": "#22c55e"}, {"name": "Other Income", "type": "income", "icon": "plus-circle", "color": "#22c55e"}, # Expenses — Housing {"name": "Rent / Mortgage", "type": "expense", "icon": "home", "color": "#6366f1"}, {"name": "Council Tax", "type": "expense", "icon": "landmark", "color": "#6366f1"}, {"name": "Home Insurance", "type": "expense", "icon": "shield", "color": "#6366f1"}, {"name": "Home Maintenance", "type": "expense", "icon": "wrench", "color": "#6366f1"}, # Utilities {"name": "Electricity", "type": "expense", "icon": "zap", "color": "#f59e0b"}, {"name": "Gas", "type": "expense", "icon": "flame", "color": "#f59e0b"}, {"name": "Water", "type": "expense", "icon": "droplets", "color": "#f59e0b"}, {"name": "Internet", "type": "expense", "icon": "wifi", "color": "#f59e0b"}, {"name": "Phone", "type": "expense", "icon": "smartphone", "color": "#f59e0b"}, # Food {"name": "Groceries", "type": "expense", "icon": "shopping-cart", "color": "#ec4899"}, {"name": "Eating Out", "type": "expense", "icon": "utensils", "color": "#ec4899"}, {"name": "Coffee", "type": "expense", "icon": "coffee", "color": "#ec4899"}, {"name": "Takeaway", "type": "expense", "icon": "package", "color": "#ec4899"}, # Transport {"name": "Fuel", "type": "expense", "icon": "fuel", "color": "#0ea5e9"}, {"name": "Public Transport", "type": "expense", "icon": "bus", "color": "#0ea5e9"}, {"name": "Car Insurance", "type": "expense", "icon": "car", "color": "#0ea5e9"}, {"name": "Car Maintenance", "type": "expense", "icon": "wrench", "color": "#0ea5e9"}, {"name": "Parking", "type": "expense", "icon": "parking-circle", "color": "#0ea5e9"}, {"name": "Taxi / Ride share", "type": "expense", "icon": "map-pin", "color": "#0ea5e9"}, # Health {"name": "Healthcare", "type": "expense", "icon": "heart-pulse", "color": "#ef4444"}, {"name": "Pharmacy", "type": "expense", "icon": "pill", "color": "#ef4444"}, {"name": "Gym", "type": "expense", "icon": "dumbbell", "color": "#ef4444"}, # Personal {"name": "Clothing", "type": "expense", "icon": "shirt", "color": "#a855f7"}, {"name": "Personal Care", "type": "expense", "icon": "sparkles", "color": "#a855f7"}, {"name": "Subscriptions", "type": "expense", "icon": "repeat", "color": "#a855f7"}, {"name": "Entertainment", "type": "expense", "icon": "tv", "color": "#a855f7"}, {"name": "Holidays", "type": "expense", "icon": "plane", "color": "#a855f7"}, # Finance {"name": "Loan Repayment", "type": "expense", "icon": "credit-card", "color": "#64748b"}, {"name": "Mortgage Payment", "type": "expense", "icon": "building", "color": "#64748b"}, {"name": "Bank Charges", "type": "expense", "icon": "landmark", "color": "#64748b"}, {"name": "Interest Paid", "type": "expense", "icon": "percent", "color": "#64748b"}, # Savings {"name": "Savings", "type": "expense", "icon": "piggy-bank", "color": "#10b981"}, {"name": "Investments", "type": "expense", "icon": "trending-up", "color": "#10b981"}, # Other {"name": "Gifts", "type": "expense", "icon": "gift", "color": "#f97316"}, {"name": "Education", "type": "expense", "icon": "graduation-cap", "color": "#f97316"}, {"name": "Other Expense", "type": "expense", "icon": "more-horizontal", "color": "#64748b"}, # Transfers {"name": "Transfer", "type": "transfer", "icon": "arrow-left-right", "color": "#94a3b8"}, ] async def seed_system_categories(db: AsyncSession) -> None: existing = await db.scalar( select(Category).where(Category.is_system == True).limit(1) ) if existing: return now = datetime.now(timezone.utc) for i, cat in enumerate(SYSTEM_CATEGORIES): db.add(Category( user_id=None, name=cat["name"], type=cat["type"], icon=cat.get("icon"), color=cat.get("color"), is_system=True, sort_order=i, created_at=now, )) await db.flush() async def list_categories(db: AsyncSession, user_id: uuid.UUID) -> list[dict]: result = await db.execute( select(Category).where( (Category.user_id == user_id) | (Category.user_id.is_(None)) ).order_by(Category.type, Category.sort_order, Category.name) ) cats = result.scalars().all() return [ { "id": str(c.id), "name": c.name, "type": c.type, "icon": c.icon, "color": c.color, "is_system": c.is_system, "parent_id": str(c.parent_id) if c.parent_id else None, "sort_order": c.sort_order, } for c in cats ] async def create_category( db: AsyncSession, user_id: uuid.UUID, name: str, type_: str, icon: str | None = None, color: str | None = None, parent_id: uuid.UUID | None = None, ) -> dict: now = datetime.now(timezone.utc) cat = Category( user_id=user_id, name=name, type=type_, icon=icon, color=color, parent_id=parent_id, is_system=False, created_at=now, ) db.add(cat) await db.flush() return {"id": str(cat.id), "name": cat.name, "type": cat.type, "icon": cat.icon, "color": cat.color, "is_system": False}