import re
import sys

def patch_file(designer_file):
    with open(designer_file, 'r', encoding='utf-8') as f:
        content = f.read()

    grids = {
        "dgv_dashboard": [
            ("AccountId", "Account ID", False, False),
            ("IsDemo", "Is Demo", False, False),
            ("IsActive", "Is Active", False, False),
            ("AccountName", "Account", True, False),
            ("TotalBalance", "Total USD", True, False),
            ("AvailableBalance", "Available", True, False),
            ("PositionBalance", "Positions", True, False),
            ("OpenTradesCount", "Open", True, False),
            ("ClosedTrades24h", "Closed 24h", True, False),
            ("Pnl24h", "Pnl 24h", True, False),
            ("Winrate24h", "Winrate 24h", True, False),
            ("ClosedTrades7d", "Closed 7d", True, False),
            ("Pnl7d", "Pnl 7d", True, False),
            ("Winrate7d", "Winrate 7d", True, False)
        ],
        "dgv_openTrades": [
            ("AccountName", "Account", True, False),
            ("SourceTraderName", "Copied From", True, True),
            ("MarketQuestion", "Market", True, True),
            ("MarketSlug", "Market Slug", False, False),
            ("Outcome", "Outcome", True, False),
            ("Side", "Side", True, False),
            ("EntryPrice", "Entry Price", True, False),
            ("Size", "Shares", True, False),
            ("AmountUsd", "Amount USD", True, False)
        ],
        "dgv_closedTrades": [
            ("TradeId", "ID", False, False),
            ("AccountId", "Account ID", False, False),
            ("SourceTraderId", "SourceTraderId", False, False),
            ("IsDemo", "Is Demo", False, False),
            ("TokenId", "TokenId", False, False),
            ("MarketSlug", "Market Slug", False, False),
            ("MarketQuestion", "Market", True, True),
            ("Outcome", "Outcome", True, False),
            ("Side", "Side", True, False),
            ("EntryPrice", "Entry Price", True, False),
            ("ExitPrice", "Exit Price", True, False),
            ("Size", "Shares", True, False),
            ("RealizedPnl", "P&L", True, False),
            ("PnlPercent", "P&L %", True, False),
            ("TotalFees", "Fees", True, False),
            ("OpenedAt", "Opened At", True, False),
            ("ClosedAt", "Closed At", True, False),
            ("ExitReason", "Reason", True, False)
        ],
        "dgv_masterTraders": [
            ("Id", "Id", False, False),
            ("WalletAddress", "Wallet", True, False),
            ("DisplayName", "Name", True, False),
            ("Category", "Category", True, False),
            ("Description", "Description", True, False),
            ("Reasoning", "Reasoning", True, False),
            ("IsActive", "Is Active", True, False),
            ("IsHidden", "Is Hidden", True, False),
            ("TotalTrades", "Trades", True, False),
            ("WinningTrades", "Wins", True, False),
            ("Winrate30t", "Winrate 30t", True, False),
            ("TotalPnl", "Total P&L", True, False)
        ],
        "dgv_SlaveTraders": [
            ("AccountId", "ID", False, False),
            ("Name", "Name", True, False),
            ("WalletAddress", "Wallet", True, False),
            ("IsDemo", "Is Demo", True, False),
            ("IsActive", "Is Active", True, False),
            ("CloseOnlyMode", "Close Only", True, False),
            ("PayoutAddress", "Payout Address", True, False),
            ("PayoutLimitUsd", "Payout Limit", True, False),
            ("PerMarketLimit", "Max %", True, False),
            ("MaxPriceDifference", "Max Price Diff", True, False),
            ("MaxBuyPrice", "Max Buy Price", True, False),
            ("ProfitTarget", "Profit Target", True, False),
            ("LimitUnder6h", "< 6h", True, False),
            ("LimitUnder24h", "< 24h", True, False),
            ("LimitUnder72h", "< 72h", True, False),
            ("LimitOver72h", "> 72h", True, False)
        ]
    }

    declarations = []
    instantiations = []
    setups = []

    for dgv_name, cols in grids.items():
        if f"{dgv_name}.Columns.AddRange" in content:
            print(f"{dgv_name} already patched.")
            continue

        col_refs = []
        for prop, header, visible, is_link in cols:
            col_type = "DataGridViewLinkColumn" if is_link else "DataGridViewTextBoxColumn"
            col_name = f"col_{dgv_name}_{prop}"
            col_refs.append(f"{col_name}")

            declarations.append(f"private {col_type} {col_name};")
            instantiations.append(f"{col_name} = new {col_type}();")

            setup = f"""// 
// {col_name}
// 
{col_name}.DataPropertyName = "{prop}";
{col_name}.HeaderText = "{header}";
{col_name}.Name = "{col_name}";
{col_name}.ReadOnly = true;
"""
            if not visible:
                setup += f"{col_name}.Visible = false;\n"
            
            if is_link:
                setup += f"{col_name}.ActiveLinkColor = Color.White;\n"
                setup += f"{col_name}.LinkBehavior = LinkBehavior.SystemDefault;\n"
                setup += f"{col_name}.LinkColor = Color.Blue;\n"
                setup += f"{col_name}.TrackVisitedState = true;\n"
                setup += f"{col_name}.VisitedLinkColor = Color.Purple;\n"

            setups.append(setup)

        add_range_code = f"{dgv_name}.Columns.AddRange(new DataGridViewColumn[] {{ " + ", ".join(col_refs) + " });\n"
        
        # find `dgv_name.Name = "..."`
        pattern = f'({dgv_name}\\.Name = "{dgv_name}";)'
        content, n = re.subn(pattern, r'\1\n            ' + add_range_code.replace('\n', '\n            '), content)
        if n == 0:
            print(f"FAILED to find {pattern}")

    if not declarations:
        print("No grids to patch or already patched.")
        return

    # Declarations
    bottom_pattern = r'(private DataGridView dgv_dashboard;)'
    decl_str = "\n        ".join(declarations) + "\n        "
    content, n = re.subn(bottom_pattern, decl_str + r'\1', content)

    # Instantiations
    top_pattern = r'(dgv_dashboard = new DataGridView\(\);)'
    inst_str = "\n            ".join(instantiations) + "\n            "
    content, n = re.subn(top_pattern, inst_str + r'\1', content)

    # Setups
    resume_pattern = r'(\(\(System\.ComponentModel\.ISupportInitialize\)dgv_dashboard\)\.EndInit\(\);)'
    setup_str = "\n            ".join("\n            ".join(s.splitlines()) for s in setups) + "\n            "
    content, n = re.subn(resume_pattern, setup_str + r'\1', content)

    with open(designer_file, 'w', encoding='utf-8') as f:
        f.write(content)

    print("Patched successfully.")

if __name__ == '__main__':
    patch_file(sys.argv[1])
