#!/usr/bin/env python3
"""
Seed script to populate item_type_definitions with standard accounting item types and GL mappings

Usage:
    python scripts/seed_item_type_definitions.py

This script:
1. Creates all 28 standard item types from ItemTypeEnum
2. Links each to the appropriate GL accounts from GLAccountMapping
3. Sets depreciation/amortization parameters for asset items
4. Sets tax treatement appropriately for each type
"""

import sys
import uuid
from datetime import datetime
from decimal import Decimal

# Add parent directory to path for imports
sys.path.insert(0, '/'.join(__file__.split('/')[:-2]))

from app.core.database import SessionLocal
from app.models.item_type_mapping import ItemTypeEnum, GLAccountMapping, ItemTypeDefinition
from app.models.accounting import AccountingCode


def find_or_create_accounting_code(db, code, name, account_type, category=None):
    """Find an accounting code by code or name, or create it if missing"""

    # If not provided, infer category from the name or account type
    if not category:
        if 'Accumulated' in name:
            category = 'Accumulated Depreciation'
        elif 'Intangible' in name or 'Patent' in name or 'License' in name or 'Software' in name:
            category = 'Intangible Assets'
        elif account_type == 'Asset':
            category = 'Fixed Asset'
        elif account_type == 'Liability':
            category = 'Current Liability'
        elif account_type == 'Expense':
            category = 'Operating Expense'
        else:
            category = 'Current Asset'

    # Try to find by code first
    if code:
        account = db.query(AccountingCode).filter(
            AccountingCode.code == code
        ).first()
        if account:
            return account

    # Try to find by name
    account = db.query(AccountingCode).filter(
        AccountingCode.name == name
    ).first()
    if account:
        return account

    # Create new if not found
    print(f"  Creating GL account: {code} - {name} ({account_type})")
    account = AccountingCode(
        id=str(uuid.uuid4()),
        code=code or name,
        name=name,
        account_type=account_type,
        category=category
    )
    db.add(account)
    db.flush()
    return account


def seed_item_type_definitions():
    """
    Seed the item_type_definitions table with all standard item types.
    """

    db = SessionLocal()

    try:
        print("=" * 80)
        print("SEEDING ITEM TYPE DEFINITIONS")
        print("=" * 80)

        # Check if already seeded
        existing_count = db.query(ItemTypeDefinition).count()
        if existing_count > 0:
            print(f"\n✓ Found {existing_count} existing item type definitions")
            response = input("Do you want to clear and reseed? (y/n): ").strip().lower()
            if response == 'y':
                print(f"Deleting {existing_count} existing definitions...")
                db.query(ItemTypeDefinition).delete()
                db.commit()
            else:
                print("Skipping seed operation")
                return

        # Get all GL account mappings
        mappings = GLAccountMapping.MAPPING

        print(f"\nProcessing {len(mappings)} item types...\n")

        created_count = 0

        for item_type, mapping_dict in mappings.items():
            print(f"  Processing: {item_type}")
            print(f"    Description: {mapping_dict.get('description', 'N/A')}")

            # Ensure accounting codes exist
            debit_account = find_or_create_accounting_code(
                db,
                code=mapping_dict.get('debit_account'),
                name=mapping_dict.get('description', item_type),
                account_type='Asset' if mapping_dict.get('is_asset', False) else 'Expense'
            )

            # Get or create accumulated depreciation account (if applicable)
            accumulated_depr_account = None
            if mapping_dict.get('accumulated_depreciation'):
                accumulated_depr_account = find_or_create_accounting_code(
                    db,
                    code=mapping_dict.get('accumulated_depreciation'),
                    name=f"{mapping_dict.get('description', item_type)} - Accumulated Depreciation",
                    account_type='Asset'
                )

            # Get or create depreciation expense account (if applicable)
            depreciation_expense_account = None
            if mapping_dict.get('depreciation_expense'):
                depreciation_expense_account = find_or_create_accounting_code(
                    db,
                    code=mapping_dict.get('depreciation_expense'),
                    name=f"Depreciation Expense - {mapping_dict.get('description', item_type)}",
                    account_type='Expense'
                )

            # Get or create accumulated amortization account (if applicable)
            accumulated_amort_account = None
            if mapping_dict.get('accumulated_amortization'):
                accumulated_amort_account = find_or_create_accounting_code(
                    db,
                    code=mapping_dict.get('accumulated_amortization'),
                    name=f"{mapping_dict.get('description', item_type)} - Accumulated Amortization",
                    account_type='Asset'
                )

            # Get or create amortization expense account (if applicable)
            amortization_expense_account = None
            if mapping_dict.get('amortization_expense'):
                amortization_expense_account = find_or_create_accounting_code(
                    db,
                    code=mapping_dict.get('amortization_expense'),
                    name=f"Amortization Expense - {mapping_dict.get('description', item_type)}",
                    account_type='Expense'
                )

            # Create ItemTypeDefinition
            item_type_def = ItemTypeDefinition(
                id=str(uuid.uuid4()),
                item_type=item_type,
                name=mapping_dict.get('description', item_type),
                description=mapping_dict.get('description', item_type),

                # Determine categorization
                is_asset=mapping_dict.get('is_asset', False),
                is_taxable=mapping_dict.get('is_taxable', True),
                requires_serial_number=mapping_dict.get('requires_serial_number', False),
                is_active=True,

                # Depreciation/Amortization fields
                useful_life_years=mapping_dict.get('useful_life_years', None),

                # GL Account relationships
                debit_account_id=debit_account.id if debit_account else None,
                accumulated_depr_account_id=accumulated_depr_account.id if accumulated_depr_account else None,
                depreciation_expense_account_id=depreciation_expense_account.id if depreciation_expense_account else None,
                accumulated_amort_account_id=accumulated_amort_account.id if accumulated_amort_account else None,
                amortization_expense_account_id=amortization_expense_account.id if amortization_expense_account else None,
            )

            db.add(item_type_def)
            created_count += 1
            print(f"    [OK] Created definition\n")

        # Commit all changes
        db.commit()

        print("=" * 80)
        print(f"[OK] SUCCESSFULLY SEEDED {created_count} ITEM TYPE DEFINITIONS")
        print("=" * 80)
        print("\nItem types created:")

        # Display summary
        definitions = db.query(ItemTypeDefinition).order_by(ItemTypeDefinition.item_type).all()

        for defn in definitions:
            debit_code = defn.debit_account.code if defn.debit_account else '????'
            print(f"    • {defn.item_type:30} ({debit_code:>5}) - {defn.name}")

        print("\n" + "=" * 80)

    except Exception as e:
        db.rollback()
        print(f"\n[ERROR] ERROR: {str(e)}")
        import traceback
        traceback.print_exc()
        sys.exit(1)

    finally:
        db.close()


if __name__ == "__main__":
    seed_item_type_definitions()
