"""
Test script for Dimensional Balance Viewing

Verifies that balances can be viewed and aggregated by dimension values.
"""

import os
import sys
from datetime import datetime, date

# Ensure workspace root is on sys.path
WORKSPACE_ROOT = os.path.dirname(os.path.dirname(__file__))
if WORKSPACE_ROOT not in sys.path:
    sys.path.append(WORKSPACE_ROOT)

from sqlalchemy import text
from app.core.database import engine, SessionLocal
from app.models.accounting import AccountingCode, JournalEntry
from app.models.accounting_dimensions import AccountingDimension, AccountingDimensionValue, AccountingDimensionAssignment
from app.services.dimensional_code_service import DimensionalCodeService


def create_test_data():
    """Create test data: dimensions, account, and journal entries with dimensional assignments."""
    db = SessionLocal()

    try:
        # Check if test dimension exists
        test_dimension = db.query(AccountingDimension).filter_by(code="TEST_DEPT").first()
        if test_dimension:
            print(f"✓ Test dimension already exists: {test_dimension.name}")
            return test_dimension.id

        # Create test dimension
        dimension = AccountingDimension(
            code="TEST_DEPT",
            name="Test Department Dimension",
            description="Test dimension for balance viewing",
            dimension_type="organizational",
            scope="global",
            is_active=True
        )
        db.add(dimension)
        db.commit()
        db.refresh(dimension)
        print(f"✓ Created test dimension: {dimension.name} (ID: {dimension.id})")

        # Create dimension values
        values = [
            {"code": "DEPT001", "name": "Sales Department"},
            {"code": "DEPT002", "name": "Marketing Department"},
            {"code": "DEPT003", "name": "IT Department"}
        ]

        created_values = []
        for val_data in values:
            dim_value = AccountingDimensionValue(
                dimension_id=dimension.id,
                code=val_data["code"],
                name=val_data["name"],
                is_active=True
            )
            db.add(dim_value)
            created_values.append(dim_value)

        db.commit()
        for dv in created_values:
            db.refresh(dv)
        print(f"✓ Created {len(created_values)} dimension values")

        # Get or create test account
        test_account = db.query(AccountingCode).filter_by(code="5000-TEST").first()
        if not test_account:
            test_account = AccountingCode(
                code="5000-TEST",
                name="Test Expense Account (Dimensional Balances)",
                account_type="Expense",
                category="Operating Expenses",
                is_parent=False,
                currency="BWP"
            )
            db.add(test_account)
            db.commit()
            db.refresh(test_account)
            print(f"✓ Created test account: {test_account.code} - {test_account.name}")
        else:
            print(f"✓ Using existing test account: {test_account.code}")

        # Create sample journal entries with dimensional assignments
        print("\nCreating test journal entries with dimensional assignments...")

        # Sales Dept: 1000 debit, 200 credit
        je1 = JournalEntry(
            accounting_code_id=test_account.id,
            accounting_entry_id=None,  # Can be null for test
            date=date.today(),
            debit_amount=1000.00,
            credit_amount=200.00,
            description="Test entry for Sales Dept"
        )
        db.add(je1)
        db.commit()
        db.refresh(je1)

        assign1 = AccountingDimensionAssignment(
            journal_entry_id=je1.id,
            dimension_id=dimension.id,
            dimension_value_id=created_values[0].id  # Sales
        )
        db.add(assign1)

        # Marketing Dept: 500 debit, 100 credit
        je2 = JournalEntry(
            accounting_code_id=test_account.id,
            accounting_entry_id=None,
            date=date.today(),
            debit_amount=500.00,
            credit_amount=100.00,
            description="Test entry for Marketing Dept"
        )
        db.add(je2)
        db.commit()
        db.refresh(je2)

        assign2 = AccountingDimensionAssignment(
            journal_entry_id=je2.id,
            dimension_id=dimension.id,
            dimension_value_id=created_values[1].id  # Marketing
        )
        db.add(assign2)

        # IT Dept: 1500 debit, 300 credit
        je3 = JournalEntry(
            accounting_code_id=test_account.id,
            accounting_entry_id=None,
            date=date.today(),
            debit_amount=1500.00,
            credit_amount=300.00,
            description="Test entry for IT Dept"
        )
        db.add(je3)
        db.commit()
        db.refresh(je3)

        assign3 = AccountingDimensionAssignment(
            journal_entry_id=je3.id,
            dimension_id=dimension.id,
            dimension_value_id=created_values[2].id  # IT
        )
        db.add(assign3)

        db.commit()
        print(f"✓ Created 3 journal entries with dimensional assignments")

        return test_account.id

    except Exception as e:
        db.rollback()
        print(f"✗ Error creating test data: {e}")
        raise
    finally:
        db.close()


def test_dimensional_balances():
    """Test fetching dimensional balances."""
    print("\n=== Testing Dimensional Balance Viewing ===")

    db = SessionLocal()
    service = DimensionalCodeService(db)

    try:
        # Get test account
        test_account = db.query(AccountingCode).filter_by(code="5000-TEST").first()
        if not test_account:
            print("✗ Test account not found. Run create_test_data first.")
            return

        print(f"\nFetching dimensional balances for account: {test_account.code} - {test_account.name}")

        # Get dimensional balances
        balances = service.get_dimensional_balances(
            base_code_id=test_account.id,
            as_of_date=date.today()
        )

        if not balances:
            print("⚠ No dimensional balances found. Ensure journal entries have dimension assignments.")
            return

        print(f"\n✓ Found {len(balances)} dimensional balance entries:\n")

        total_debits = 0.0
        total_credits = 0.0
        total_net = 0.0

        # Group by dimension type
        by_type = {}
        for balance in balances:
            dim_type = balance['dimension_type']
            if dim_type not in by_type:
                by_type[dim_type] = []
            by_type[dim_type].append(balance)

        for dim_type, items in by_type.items():
            print(f"📊 Dimension Type: {dim_type.upper()}")
            print("-" * 80)
            print(f"{'Code':<15} {'Value':<30} {'Debits':>15} {'Credits':>15} {'Net Balance':>15}")
            print("-" * 80)

            for item in items:
                print(f"{item['dimension_value_code']:<15} {item['dimension_value_name']:<30} "
                      f"{item['total_debits']:>15.2f} {item['total_credits']:>15.2f} "
                      f"{item['net_balance']:>15.2f}")

                total_debits += item['total_debits']
                total_credits += item['total_credits']
                total_net += item['net_balance']

            print("-" * 80)
            print()

        print("=" * 80)
        print(f"{'TOTALS':<45} {total_debits:>15.2f} {total_credits:>15.2f} {total_net:>15.2f}")
        print("=" * 80)

        # Test with dimension type filter
        print("\n\nTesting with dimension type filter (organizational)...")
        filtered_balances = service.get_dimensional_balances(
            base_code_id=test_account.id,
            as_of_date=date.today(),
            dimension_types=["organizational"]
        )

        print(f"✓ Found {len(filtered_balances)} balances for 'organizational' dimension type")

        print("\n✓ Dimensional balance viewing test completed successfully!")

    except Exception as e:
        print(f"\n✗ Error testing dimensional balances: {e}")
        import traceback
        traceback.print_exc()
    finally:
        db.close()


def run_all_tests():
    """Run all tests."""
    print("=" * 80)
    print("Dimensional Balance Viewing - Test Suite")
    print("=" * 80)

    try:
        # Create test data
        account_id = create_test_data()

        # Test dimensional balances
        test_dimensional_balances()

        print("\n" + "=" * 80)
        print("✓ All tests completed successfully!")
        print("=" * 80)
        print(f"\nYou can now test the UI:")
        print(f"1. Navigate to: http://localhost:8010/static/dimensional-balances.html")
        print(f"2. Select account '5000-TEST - Test Expense Account'")
        print(f"3. Click 'View Balances' to see the dimensional breakdown")

    except Exception as e:
        print("\n" + "=" * 80)
        print(f"✗ Test failed: {e}")
        print("=" * 80)
        import traceback
        traceback.print_exc()


if __name__ == '__main__':
    run_all_tests()
