async def m001_initial(db):
    """
    Initial migration for Castle accounting extension.
    Creates tables for double-entry bookkeeping system.
    """
    await db.execute(
        f"""
        CREATE TABLE accounts (
            id TEXT PRIMARY KEY,
            name TEXT NOT NULL,
            account_type TEXT NOT NULL,
            description TEXT,
            user_id TEXT,
            created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
        );
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_accounts_user_id ON accounts (user_id);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_accounts_type ON accounts (account_type);
        """
    )

    await db.execute(
        f"""
        CREATE TABLE journal_entries (
            id TEXT PRIMARY KEY,
            description TEXT NOT NULL,
            entry_date TIMESTAMP NOT NULL,
            created_by TEXT NOT NULL,
            created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
            reference TEXT
        );
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_journal_entries_created_by ON journal_entries (created_by);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_journal_entries_date ON journal_entries (entry_date);
        """
    )

    await db.execute(
        f"""
        CREATE TABLE entry_lines (
            id TEXT PRIMARY KEY,
            journal_entry_id TEXT NOT NULL,
            account_id TEXT NOT NULL,
            debit INTEGER NOT NULL DEFAULT 0,
            credit INTEGER NOT NULL DEFAULT 0,
            description TEXT,
            metadata TEXT DEFAULT '{{}}'
        );
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_entry_lines_journal_entry ON entry_lines (journal_entry_id);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_entry_lines_account ON entry_lines (account_id);
        """
    )

    # Insert default chart of accounts
    default_accounts = [
        # Assets
        ("cash", "Cash", "asset", "Cash on hand"),
        ("bank", "Bank Account", "asset", "Bank account"),
        ("lightning", "Lightning Balance", "asset", "Lightning Network balance"),
        ("accounts_receivable", "Accounts Receivable", "asset", "Money owed to the Castle"),

        # Liabilities
        ("accounts_payable", "Accounts Payable", "liability", "Money owed by the Castle"),

        # Equity
        ("member_equity", "Member Equity", "equity", "Member contributions"),
        ("retained_earnings", "Retained Earnings", "equity", "Accumulated profits"),

        # Revenue
        ("accommodation_revenue", "Accommodation Revenue", "revenue", "Revenue from stays"),
        ("service_revenue", "Service Revenue", "revenue", "Revenue from services"),
        ("other_revenue", "Other Revenue", "revenue", "Other revenue"),

        # Expenses
        ("utilities", "Utilities", "expense", "Electricity, water, internet"),
        ("food", "Food & Supplies", "expense", "Food and supplies"),
        ("maintenance", "Maintenance", "expense", "Repairs and maintenance"),
        ("other_expense", "Other Expenses", "expense", "Miscellaneous expenses"),
    ]

    for acc_id, name, acc_type, desc in default_accounts:
        await db.execute(
            """
            INSERT INTO accounts (id, name, account_type, description)
            VALUES (:id, :name, :type, :description)
            """,
            {"id": acc_id, "name": name, "type": acc_type, "description": desc}
        )


async def m002_extension_settings(db):
    """
    Create extension_settings table for Castle configuration.
    """
    await db.execute(
        f"""
        CREATE TABLE extension_settings (
            id TEXT NOT NULL PRIMARY KEY,
            castle_wallet_id TEXT,
            updated_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
        );
        """
    )


async def m003_user_wallet_settings(db):
    """
    Create user_wallet_settings table for per-user wallet configuration.
    """
    await db.execute(
        f"""
        CREATE TABLE user_wallet_settings (
            id TEXT NOT NULL PRIMARY KEY,
            user_wallet_id TEXT,
            updated_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
        );
        """
    )


async def m004_manual_payment_requests(db):
    """
    Create manual_payment_requests table for user payment requests to Castle.
    """
    await db.execute(
        f"""
        CREATE TABLE manual_payment_requests (
            id TEXT PRIMARY KEY,
            user_id TEXT NOT NULL,
            amount INTEGER NOT NULL,
            description TEXT NOT NULL,
            status TEXT NOT NULL DEFAULT 'pending',
            created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
            reviewed_at TIMESTAMP,
            reviewed_by TEXT,
            journal_entry_id TEXT
        );
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_manual_payment_requests_user_id ON manual_payment_requests (user_id);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_manual_payment_requests_status ON manual_payment_requests (status);
        """
    )


async def m005_add_flag_and_meta(db):
    """
    Add flag and meta columns to journal_entries table.
    - flag: Transaction status (* = cleared, ! = pending, # = flagged, x = void)
    - meta: JSON metadata for audit trail (source, tags, links, notes)
    """
    await db.execute(
        """
        ALTER TABLE journal_entries ADD COLUMN flag TEXT DEFAULT '*';
        """
    )

    await db.execute(
        """
        ALTER TABLE journal_entries ADD COLUMN meta TEXT DEFAULT '{}';
        """
    )


async def m006_hierarchical_account_names(db):
    """
    Migrate account names to hierarchical Beancount-style format.
    - "Cash" → "Assets:Cash"
    - "Accounts Receivable" → "Assets:Receivable"
    - "Food & Supplies" → "Expenses:Food:Supplies"
    - "Accounts Receivable - af983632" → "Assets:Receivable:User-af983632"
    """
    from .account_utils import migrate_account_name
    from .models import AccountType

    # Get all existing accounts
    accounts = await db.fetchall("SELECT * FROM accounts")

    # Mapping of old names to new names
    name_mappings = {
        # Assets
        "cash": "Assets:Cash",
        "bank": "Assets:Bank",
        "lightning": "Assets:Bitcoin:Lightning",
        "accounts_receivable": "Assets:Receivable",

        # Liabilities
        "accounts_payable": "Liabilities:Payable",

        # Equity
        "member_equity": "Equity:MemberEquity",
        "retained_earnings": "Equity:RetainedEarnings",

        # Revenue → Income
        "accommodation_revenue": "Income:Accommodation",
        "service_revenue": "Income:Service",
        "other_revenue": "Income:Other",

        # Expenses
        "utilities": "Expenses:Utilities",
        "food": "Expenses:Food:Supplies",
        "maintenance": "Expenses:Maintenance",
        "other_expense": "Expenses:Other",
    }

    # Update default accounts using ID-based mapping
    for old_id, new_name in name_mappings.items():
        await db.execute(
            """
            UPDATE accounts
            SET name = :new_name
            WHERE id = :old_id
            """,
            {"new_name": new_name, "old_id": old_id}
        )

    # Update user-specific accounts (those with user_id set)
    user_accounts = await db.fetchall(
        "SELECT * FROM accounts WHERE user_id IS NOT NULL"
    )

    for account in user_accounts:
        # Parse account type
        account_type = AccountType(account["account_type"])

        # Migrate name
        new_name = migrate_account_name(account["name"], account_type)

        await db.execute(
            """
            UPDATE accounts
            SET name = :new_name
            WHERE id = :id
            """,
            {"new_name": new_name, "id": account["id"]}
        )


async def m007_balance_assertions(db):
    """
    Create balance_assertions table for reconciliation.
    Allows admins to assert expected balances at specific dates.
    """
    await db.execute(
        f"""
        CREATE TABLE balance_assertions (
            id TEXT PRIMARY KEY,
            date TIMESTAMP NOT NULL,
            account_id TEXT NOT NULL,
            expected_balance_sats INTEGER NOT NULL,
            expected_balance_fiat TEXT,
            fiat_currency TEXT,
            tolerance_sats INTEGER DEFAULT 0,
            tolerance_fiat TEXT DEFAULT '0',
            checked_balance_sats INTEGER,
            checked_balance_fiat TEXT,
            difference_sats INTEGER,
            difference_fiat TEXT,
            status TEXT NOT NULL DEFAULT 'pending',
            created_by TEXT NOT NULL,
            created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
            checked_at TIMESTAMP,
            FOREIGN KEY (account_id) REFERENCES accounts (id)
        );
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_balance_assertions_account_id ON balance_assertions (account_id);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_balance_assertions_status ON balance_assertions (status);
        """
    )

    await db.execute(
        """
        CREATE INDEX idx_balance_assertions_date ON balance_assertions (date);
        """
    )


async def m008_rename_lightning_account(db):
    """
    Rename Lightning account from Assets:Lightning:Balance to Assets:Bitcoin:Lightning
    for better naming consistency.
    """
    await db.execute(
        """
        UPDATE accounts
        SET name = 'Assets:Bitcoin:Lightning'
        WHERE name = 'Assets:Lightning:Balance'
        """
    )


async def m009_add_onchain_bitcoin_account(db):
    """
    Add Assets:Bitcoin:OnChain account for on-chain Bitcoin transactions.
    This allows tracking on-chain Bitcoin separately from Lightning Network payments.
    """
    import uuid

    # Check if the account already exists
    existing = await db.fetchone(
        """
        SELECT id FROM accounts
        WHERE name = 'Assets:Bitcoin:OnChain'
        """
    )

    if not existing:
        # Create the on-chain Bitcoin asset account
        await db.execute(
            f"""
            INSERT INTO accounts (id, name, account_type, description, created_at)
            VALUES (:id, :name, :type, :description, {db.timestamp_now})
            """,
            {
                "id": str(uuid.uuid4()),
                "name": "Assets:Bitcoin:OnChain",
                "type": "asset",
                "description": "On-chain Bitcoin wallet"
            }
        )
