"""OpenBB Workspace Application.

This includes widgets and endpoints for fetching and displaying
SEC filings, as well as calendars for earnings, dividends, and IPOs.

To use this app, launch it with:

```sh
openbb-api --app openbb_nasdaq.app:main --factory
```

Then navigate to the OpenBB Workspace and add the server as a backend data source.

Open the server's URL in your browser for more information on connecting to the OpenBB Workspace.
"""

# pylint: disable=too-many-statements, too-many-locals, line-too-long


def main():
    """Return a FastAPI app instance."""
    # pylint: disable=import-outside-toplevel
    from datetime import datetime
    from typing import Annotated, Any, Literal

    from async_lru import alru_cache
    from fastapi import Depends, FastAPI
    from openbb_nasdaq.models.calendar_dividend import NasdaqCalendarDividendFetcher
    from openbb_nasdaq.models.calendar_earnings import NasdaqCalendarEarningsFetcher
    from openbb_nasdaq.models.calendar_ipo import NasdaqCalendarIpoFetcher
    from openbb_nasdaq.models.company_filings import NasdaqCompanyFilingsFetcher
    from openbb_nasdaq.models.economic_calendar import NasdaqEconomicCalendarFetcher
    from openbb_nasdaq.models.equity_search import NasdaqEquitySearchFetcher
    from openbb_nasdaq.models.historical_dividends import (
        NasdaqHistoricalDividendsFetcher,
    )
    from pandas import DataFrame

    listings = DataFrame()

    current_year = int(datetime.now().year)
    years = sorted(
        [{"label": str(i), "value": i} for i in range(1994, current_year + 1)],
        key=lambda x: x["value"],  # type: ignore
        reverse=True,
    )

    app = FastAPI()

    async def get_listings() -> DataFrame:
        """Get the Nasdaq listings."""
        return listings

    Nasdaqlistings = Annotated[
        DataFrame,
        Depends(get_listings),
    ]

    async def startup_event():
        """Startup event for the FastAPI app."""
        nonlocal listings
        fetcher = NasdaqEquitySearchFetcher()

        directory = await fetcher.fetch_data({}, {})

        listings = DataFrame([d.model_dump() for d in directory]).query(  # type: ignore
            "test_issue == 'N' and etf == 'N'"
            " and not name.str.contains('%')"
            " and not name.str.contains('Unit')"
            " and not name.str.contains('Rights')"
            " and not name.str.contains('Warrant')"
            " and not name.str.contains('Preferred')"
        )

    app.add_event_handler("startup", startup_event)

    @app.get("/get_symbol_choices", include_in_schema=False)
    async def get_symbol_choices(
        directory: Nasdaqlistings,  # type: ignore
        symbol: str | None = None,
        year: int | None = None,
        form_group: str | None = None,
    ) -> list:
        """Get symbol choices for the Nasdaq listings."""

        if symbol and year and form_group:
            return await get_document_choices(symbol, year, form_group)

        items = directory.set_index("symbol")["name"].to_dict()

        return [
            {"value": k, "label": k, "extraInfo": {"description": v}}
            for k, v in items.items()
        ]

    @alru_cache
    async def get_document_choices(
        symbol: str | None = None,
        year: int | None = None,
        form_group: Literal[
            "annual",
            "quarterly",
            "proxy",
            "insider",
            "8k",
            "registration",
            "comment",
        ] = "8k",
    ) -> list:
        """Get document choices for the given symbol."""
        fetcher = NasdaqCompanyFilingsFetcher()

        params = {
            "symbol": symbol,
            "year": year,
            "form_group": form_group,
        }

        items = await fetcher.fetch_data(params, {})
        docs: list = []

        for item in items:
            form = item.model_dump()  # type: ignore
            title = f"{form.get('filing_date', '')} - {'8-K' if form_group == '8k' else form_group.title()}"
            url = form.get("pdf_url")

            if not url:
                continue
            docs.append({"label": title, "value": url})

        return docs

    @alru_cache(maxsize=128)
    async def download_pdf_file(document_url: str):
        """Download a PDF file from the given URL."""
        # pylint: disable=import-outside-toplevel
        import base64  # noqa
        from openbb_core.provider.utils.helpers import make_request

        response = make_request(document_url)
        response.raise_for_status()
        encoded_content = base64.b64encode(response.content).decode("utf-8")

        return encoded_content

    @app.get(
        "/open_document",
        include_in_schema=False,
    )
    async def open_document(
        document_url: str,
    ) -> dict[str, Any]:
        """Open the selected PDF filing document."""
        encoded_content: str = ""
        error_message: str = ""

        try:
            if document_url and document_url.startswith("http"):
                encoded_content = await download_pdf_file(document_url)

        except Exception as e:  # pylint: disable=broad-except
            error_message = f"Error fetching document: {e.args[0]}"

        symbol = document_url.split("&symbol=", maxsplit=1)[1].split("&", maxsplit=1)[0]
        form_type = (
            document_url.split("&formType=", maxsplit=1)[1]
            .split("&", maxsplit=1)[0]
            .replace("-", "")
        )
        date_str = document_url.split("&dateFiled=", maxsplit=1)[1][:10].replace(
            "-", ""
        )
        filename = f"{symbol}-{date_str}-{form_type}.pdf"
        content: dict[str, Any] = {}
        if error_message != "":
            content = {
                "error_type": "download_error",
                "content": error_message,
            }
        else:
            content = {
                "content": encoded_content,
                "data_format": {
                    "data_type": "pdf",
                    "filename": filename,
                },
            }

        return content

    @app.post(
        "/open_document",
        openapi_extra={
            "widget_config": {
                "type": "multi_file_viewer",
                "name": "SEC Filings",
                "description": "View SEC filings by company.",
                "refetchInterval": False,
                "widgetId": "nasdaq_company_filings",
                "params": [
                    {
                        "paramName": "symbol",
                        "label": "Symbol",
                        "description": (
                            "Ticker symbol for the company."
                            " Foreign (dual-listed) companies may not be required to file with the SEC."
                        ),
                        "type": "endpoint",
                        "value": "AAPL",
                        "optionsEndpoint": "/get_symbol_choices",
                        "style": {"popupWidth": 850},
                    },
                    {
                        "paramName": "document_url",
                        "label": "Document URL",
                        "description": "Select the document to open.",
                        "type": "endpoint",
                        "optionsEndpoint": "/get_symbol_choices",
                        "optionsParams": {
                            "symbol": "$symbol",
                            "year": "$year",
                            "form_group": "$form_group",
                        },
                        "show": False,
                        "roles": ["fileSelector"],
                        "multiSelect": True,
                    },
                    {
                        "paramName": "year",
                        "label": "Calendar Year",
                        "description": "Calendar year for the filings.",
                        "value": years[0]["value"],
                        "type": "number",
                        "options": years,
                    },
                    {
                        "paramName": "form_group",
                        "label": "Form Group",
                        "description": "Form group for the filings.",
                        "value": "8k",
                        "type": "text",
                        "options": [
                            {"label": "Annual", "value": "annual"},
                            {"label": "Quarterly", "value": "quarterly"},
                            {"label": "Proxy", "value": "proxy"},
                            {"label": "Insider", "value": "insider"},
                            {"label": "8-K", "value": "8k"},
                            {"label": "Registration", "value": "registration"},
                            {"label": "Comment", "value": "comment"},
                        ],
                    },
                ],
                "gridData": {"w": 40, "h": 30},
            }
        },
    )
    async def post_open_document(
        params: dict,
    ) -> list:
        """POST request to open the selected PDF filing document(s)."""
        urls = params.get("document_url", [])
        documents: list = []
        if urls:
            for document_url in urls:
                if document_url.startswith("http"):
                    document = await open_document(document_url)
                    if document:
                        documents.append(document)

        return documents

    @app.get(
        "/earnings_calendar",
        openapi_extra={
            "widget_config": {
                "name": "Earnings Calendar",
                "description": "Upcoming, and historical, company earnings releases (US Markets).",
                "category": "Equity",
                "subCategory": "Calendar",
                "type": "table",
                "widgetId": "nasdaq_earnings_calendar",
                "refetchInterval": False,
                "params": [
                    {
                        "paramName": "symbol",
                        "show": False,
                        "type": "endpoint",
                        "value": "AAPL",
                        "optionsEndpoint": "/get_symbol_choices",
                        "style": {"popupWidth": 850},
                    },
                    {
                        "label": "Start Date",
                        "description": "Start date of the data.",
                        "type": "date",
                        "value": None,
                        "paramName": "start_date",
                    },
                    {
                        "label": "End Date",
                        "description": "End date of the data.",
                        "type": "date",
                        "value": None,
                        "paramName": "end_date",
                    },
                ],
                "gridData": {"w": 40, "h": 20},
                "data": {
                    "table": {
                        "enableAdvanced": True,
                        "columnsDefs": [
                            {
                                "field": "surprise_percent",
                                "formatterFn": "normalizedPercent",
                                "cellDataType": "number",
                                "renderFn": "greenRed",
                            },
                            {
                                "field": "symbol",
                                "headerTooltip": "Click on a ticker in the column to change the SEC documents viewer.",
                                "renderFn": "cellOnClick",
                                "renderFnParams": {
                                    "actionType": "groupBy",
                                    "groupByParamName": "symbol",
                                },
                            },
                            {
                                "field": "name",
                                "pinned": "left",
                            },
                        ],
                    }
                },
            },
        },
    )
    async def earnings_calendar(
        start_date: str | None = None,
        end_date: str | None = None,
    ) -> list[NasdaqCalendarEarningsFetcher.data_type]:
        """Get the earnings calendar."""
        fetcher = NasdaqCalendarEarningsFetcher()

        params = {
            "start_date": start_date,
            "end_date": end_date,
        }

        return await fetcher.fetch_data(params, {})  # type: ignore

    @app.get(
        "/dividend_calendar",
        openapi_extra={
            "widget_config": {
                "name": "Dividend Calendar",
                "description": "Upcoming, and historical, dividend payments (US Markets).",
                "category": "Equity",
                "subCategory": "Calendar",
                "type": "table",
                "widgetId": "nasdaq_dividends_calendar",
                "refetchInterval": False,
                "params": [
                    {
                        "paramName": "symbol2",
                        "show": False,
                        "type": "endpoint",
                        "value": "AAPL",
                        "optionsEndpoint": "/get_symbol_choices",
                        "style": {"popupWidth": 850},
                    },
                    {
                        "label": "Start Date",
                        "description": "Start date of the data.",
                        "type": "date",
                        "value": None,
                        "paramName": "start_date",
                    },
                    {
                        "label": "End Date",
                        "description": "End date of the data.",
                        "type": "date",
                        "value": None,
                        "paramName": "end_date",
                    },
                ],
                "gridData": {"w": 40, "h": 20},
                "data": {
                    "table": {
                        "enableAdvanced": True,
                        "columnsDefs": [
                            {
                                "field": "symbol",
                                "headerTooltip": "Click on a ticker in the column to update the historical dividends.",
                                "renderFn": "cellOnClick",
                                "renderFnParams": {
                                    "actionType": "groupBy",
                                    "groupByParamName": "symbol2",
                                },
                            },
                            {
                                "field": "name",
                                "pinned": "left",
                            },
                        ],
                    }
                },
            }
        },
    )
    async def dividend_calendar(
        start_date: str | None = None,
        end_date: str | None = None,
    ) -> list[NasdaqCalendarDividendFetcher.data_type]:
        """Get the dividend calendar."""
        fetcher = NasdaqCalendarDividendFetcher()

        params = {
            "start_date": start_date,
            "end_date": end_date,
        }

        return await fetcher.fetch_data(params, {})  # type: ignore

    @app.get(
        "/historical_dividends",
        openapi_extra={
            "widget_config": {
                "name": "Historical Dividends",
                "description": "Historical dividend payments for a given symbol.",
                "category": "Equity",
                "subCategory": "Dividends",
                "type": "table",
                "widgetId": "nasdaq_historical_dividends",
                "refetchInterval": False,
                "params": [
                    {
                        "paramName": "symbol2",
                        "label": "Symbol",
                        "description": (
                            "Select a ticker from the dividend calendar to update the historical dividends."
                        ),
                        "type": "endpoint",
                        "value": "AAPL",
                        "optionsEndpoint": "/get_symbol_choices",
                        "style": {"popupWidth": 850},
                    },
                    {
                        "label": "Start Date",
                        "description": (
                            "Start date of the data, in YYYY-MM-DD format.(Default: 5 years ago)"
                        ),
                        "optional": True,
                        "type": "date",
                        "value": None,
                        "show": True,
                        "paramName": "start_date",
                    },
                    {
                        "label": "End Date",
                        "description": (
                            "End date of the data, in YYYY-MM-DD format.(Default: today)"
                        ),
                        "optional": True,
                        "type": "date",
                        "value": None,
                        "show": True,
                        "paramName": "end_date",
                    },
                ],
            }
        },
        response_model=list[NasdaqHistoricalDividendsFetcher.data_type],
    )
    async def historical_dividends(
        symbol2: str,
        start_date: str | None = None,
        end_date: str | None = None,
    ):
        """Get historical dividends for a given symbol."""
        fetcher = NasdaqHistoricalDividendsFetcher()

        params = {
            "symbol": symbol2,
            "start_date": start_date,
            "end_date": end_date,
        }

        return await fetcher.fetch_data(params, {})

    @app.get(
        "/ipo_calendar",
        openapi_extra={
            "widget_config": {
                "name": "IPO Calendar",
                "description": "IPO announcements and calendar.",
                "category": "Equity",
                "subCategory": "Calendar",
                "type": "table",
                "widgetId": "nasdaq_ipo_calendar",
                "refetchInterval": False,
                "params": [
                    {
                        "paramName": "symbol3",
                        "show": False,
                        "type": "endpoint",
                        "value": "AAPL",
                        "optionsEndpoint": "/get_symbol_choices",
                        "style": {"popupWidth": 850},
                    },
                    {
                        "label": "Start Date",
                        "description": "Start date of the data, in YYYY-MM-DD format.",
                        "optional": True,
                        "type": "date",
                        "value": None,
                        "show": True,
                        "paramName": "start_date",
                    },
                    {
                        "label": "End Date",
                        "description": "End date of the data, in YYYY-MM-DD format.",
                        "optional": True,
                        "type": "date",
                        "value": None,
                        "show": True,
                        "paramName": "end_date",
                    },
                    {
                        "label": "Status",
                        "description": "Status of the IPO. [upcoming, priced, or withdrawn]",
                        "optional": True,
                        "type": "text",
                        "value": None,
                        "show": True,
                        "options": [
                            {"label": "upcoming", "value": "upcoming"},
                            {"label": "priced", "value": "priced"},
                            {"label": "filed", "value": "filed"},
                            {"label": "withdrawn", "value": "withdrawn"},
                        ],
                        "paramName": "status",
                    },
                    {
                        "label": "Is SPO",
                        "description": "If True, returns data for secondary public offerings (SPOs).",
                        "optional": True,
                        "type": "boolean",
                        "value": False,
                        "show": True,
                        "paramName": "is_spo",
                    },
                ],
                "gridData": {"w": 40, "h": 20},
                "data": {
                    "table": {
                        "enableAdvanced": True,
                        "columnsDefs": [
                            {
                                "field": "symbol",
                                "headerTooltip": "Click on a ticker in the column to update the historical dividends.",
                                "renderFn": "cellOnClick",
                                "renderFnParams": {
                                    "actionType": "groupBy",
                                    "groupByParamName": "symbol3",
                                },
                            },
                            {
                                "field": "name",
                                "pinned": "left",
                            },
                        ],
                    }
                },
            }
        },
    )
    async def ipo_calendar(
        start_date: str | None = None,
        end_date: str | None = None,
    ) -> list[NasdaqCalendarIpoFetcher.data_type]:
        """Get the IPO calendar."""
        fetcher = NasdaqCalendarIpoFetcher()

        params = {
            "start_date": start_date,
            "end_date": end_date,
        }

        return await fetcher.fetch_data(params, {})  # type: ignore

    @app.get(
        "/economic_calendar",
        openapi_extra={
            "widget_config": {
                "name": "Economic Calendar",
                "description": "Upcoming, and historical, macroeconomic events.",
                "category": "Economy",
                "subCategory": "Calendar",
                "type": "table",
                "widgetId": "nasdaq_economic_calendar",
                "refetchInterval": False,
                "params": [
                    {
                        "paramName": "country",
                        "options": [
                            {"label": "United States", "value": "united_states"},
                            {"label": "China", "value": "china"},
                            {"label": "Hong Kong", "value": "hong_kong"},
                            {"label": "Japan", "value": "japan"},
                            {"label": "Singapore", "value": "singapore"},
                            {"label": "South Korea", "value": "south_korea"},
                            {"label": "India", "value": "india"},
                            {"label": "Russia", "value": "russia"},
                            {"label": "Euro Zone", "value": "euro_zone"},
                            {"label": "Germany", "value": "germany"},
                            {"label": "United Kingdom", "value": "united_kingdom"},
                            {"label": "France", "value": "france"},
                            {"label": "Spain", "value": "spain"},
                            {"label": "Italy", "value": "italy"},
                            {"label": "Switzerland", "value": "switzerland"},
                            {"label": "Canada", "value": "canada"},
                            {"label": "Australia", "value": "australia"},
                            {"label": "New Zealand", "value": "new_zealand"},
                            {"label": "South Africa", "value": "south_africa"},
                            {"label": "Brazil", "value": "brazil"},
                        ],
                    },
                ],
                "gridData": {"w": 40, "h": 20},
                "data": {
                    "table": {
                        "showAll": False,
                        "enableAdvanced": True,
                        "columnsDefs": [
                            {
                                "field": "date",
                                "pinned": "left",
                                "formatterFn": None,
                                "headerName": "Date",
                                "headerTooltip": "The date of the data.",
                                "cellDataType": "date",
                            },
                            {
                                "field": "country",
                                "formatterFn": None,
                                "headerName": "Country",
                                "headerTooltip": "Country of event.",
                                "cellDataType": "text",
                            },
                            {
                                "field": "event",
                                "formatterFn": None,
                                "renderFn": "hoverCard",
                                "renderFnParams": {
                                    "hoverCard": {
                                        "cellField": "value",
                                        "markdown": "{description}",
                                    }
                                },
                                "headerName": "Event",
                                "headerTooltip": "Event name.",
                                "cellDataType": "text",
                            },
                            {
                                "field": "consensus",
                                "formatterFn": None,
                                "headerName": "Consensus",
                                "headerTooltip": "Average forecast among a representative group of economists.",
                                "cellDataType": "number",
                            },
                            {
                                "field": "actual",
                                "formatterFn": None,
                                "headerName": "Actual",
                                "headerTooltip": "Latest released value.",
                                "cellDataType": "number",
                            },
                            {
                                "field": "previous",
                                "formatterFn": None,
                                "headerName": "Previous",
                                "headerTooltip": (
                                    "Value for the previous period after"
                                    + " the revision (if revision is applicable)."
                                ),
                                "cellDataType": "number",
                            },
                            {
                                "field": "revised",
                                "formatterFn": None,
                                "headerName": "Revised",
                                "headerTooltip": "Revised previous value, if applicable.",
                                "cellDataType": "number",
                            },
                        ],
                    }
                },
            }
        },
    )
    async def economic_calendar(
        start_date: str | None = None,
        end_date: str | None = None,
        country: str | None = None,
    ):
        """Get the dividend calendar."""
        fetcher = NasdaqEconomicCalendarFetcher()

        params = {
            "start_date": start_date,
            "end_date": end_date,
        }
        if country:
            params["country"] = country

        data: list[NasdaqEconomicCalendarFetcher.data_type] = await fetcher.fetch_data(params, {})  # type: ignore
        output: list = []

        for row in data:
            markdown = (
                f"### **{row.event}**\n\n{row.description}"
                if row.description
                else row.event
            )
            output.append(
                {
                    "date": row.date.strftime("%Y-%m-%d"),
                    "country": row.country,
                    "event": {
                        "value": row.event,
                        "description": markdown,
                    },
                    "consensus": row.consensus,
                    "actual": row.actual,
                    "previous": row.previous,
                    "revised": row.revised,
                }
            )

        return output

    @app.get(
        "/apps.json",
        include_in_schema=False,
    )
    async def get_apps() -> dict:
        return {
            "name": "Company Filings & Market Calendars",
            "img": "https://logosandtypes.com/wp-content/uploads/2020/07/nasdaq.svg",
            "img_dark": "",
            "img_light": "",
            "description": (
                "View company filings and market calendars, downloaded from the public Nasdaq website."
                " This app is not affiliated with, or authoriazed by, Nasdaq."
            ),
            "allowCustomization": True,
            "tabs": {
                "earnings": {
                    "id": "earnings",
                    "name": "Earnings Calendar & Filings",
                    "layout": [
                        {
                            "i": "nasdaq_earnings_calendar",
                            "x": 0,
                            "y": 2,
                            "w": 40,
                            "h": 10,
                            "state": {
                                "chartView": {"enabled": False, "chartType": "line"},
                                "columnState": {
                                    "default": {
                                        "sort": {
                                            "sortModel": [
                                                {"colId": "market_cap", "sort": "desc"}
                                            ]
                                        },
                                        "columnPinning": {
                                            "leftColIds": [
                                                "symbol",
                                                "name",
                                                "period_ending",
                                            ],
                                            "rightColIds": [],
                                        },
                                        "columnOrder": {
                                            "orderedColIds": [
                                                "report_date",
                                                "reporting_time",
                                                "symbol",
                                                "name",
                                                "market_cap",
                                                "eps_previous",
                                                "eps_consensus",
                                                "num_estimates",
                                                "eps_actual",
                                                "surprise_percent",
                                                "period_ending",
                                                "previous_report_date",
                                            ]
                                        },
                                    }
                                },
                            },
                        },
                        {
                            "i": "nasdaq_company_filings",
                            "x": 0,
                            "y": 12,
                            "w": 40,
                            "h": 30,
                        },
                    ],
                },
                "dividend-calendar": {
                    "id": "dividend-calendar",
                    "name": "Dividend Calendar",
                    "layout": [
                        {
                            "i": "nasdaq_dividends_calendar",
                            "x": 0,
                            "y": 2,
                            "w": 40,
                            "h": 20,
                            "state": {
                                "chartView": {"enabled": False, "chartType": "line"},
                                "columnState": {
                                    "default": {
                                        "sort": {
                                            "sortModel": [
                                                {
                                                    "colId": "ex_dividend_date",
                                                    "sort": "asc",
                                                },
                                                {"colId": "amount", "sort": "desc"},
                                                {
                                                    "colId": "annualized_amount",
                                                    "sort": "desc",
                                                },
                                            ]
                                        },
                                        "columnPinning": {
                                            "leftColIds": ["symbol", "name"],
                                            "rightColIds": [],
                                        },
                                        "columnOrder": {
                                            "orderedColIds": [
                                                "ex_dividend_date",
                                                "symbol",
                                                "amount",
                                                "name",
                                                "record_date",
                                                "payment_date",
                                                "declaration_date",
                                                "annualized_amount",
                                            ]
                                        },
                                    }
                                },
                            },
                        },
                        {
                            "i": "nasdaq_historical_dividends",
                            "x": 0,
                            "y": 12,
                            "w": 40,
                            "h": 30,
                        },
                    ],
                },
                "ipo-calendar": {
                    "id": "ipo-calendar",
                    "name": "IPO Calendar",
                    "layout": [
                        {
                            "i": "nasdaq_ipo_calendar",
                            "x": 0,
                            "y": 2,
                            "w": 40,
                            "h": 15,
                            "state": {
                                "chartView": {"enabled": False, "chartType": "line"},
                                "columnState": {
                                    "default": {
                                        "columnPinning": {
                                            "leftColIds": [
                                                "ipo_date",
                                                "symbol",
                                                "name",
                                            ],
                                            "rightColIds": [],
                                        },
                                        "columnOrder": {
                                            "orderedColIds": [
                                                "ipo_date",
                                                "symbol",
                                                "name",
                                                "offer_amount",
                                                "share_count",
                                                "share_price",
                                                "deal_status",
                                                "exchange",
                                                "id",
                                            ]
                                        },
                                    }
                                },
                            },
                        },
                        {
                            "i": "nasdaq_company_filings",
                            "x": 0,
                            "y": 16,
                            "w": 40,
                            "h": 30,
                            "state": {
                                "params": {
                                    "form_group": "registration",
                                }
                            },
                        },
                    ],
                },
                "economic-calendar": {
                    "id": "economic-calendar",
                    "name": "Economic Calendar",
                    "layout": [
                        {
                            "i": "nasdaq_economic_calendar",
                            "x": 0,
                            "y": 2,
                            "w": 40,
                            "h": 20,
                            "state": {
                                "chartView": {"enabled": False, "chartType": "line"},
                                "columnState": {
                                    "default": {
                                        "sort": {
                                            "sortModel": [
                                                {"colId": "date", "sort": "desc"}
                                            ]
                                        },
                                        "columnPinning": {
                                            "leftColIds": ["date"],
                                            "rightColIds": [],
                                        },
                                    }
                                },
                            },
                        }
                    ],
                },
            },
            "groups": [
                {
                    "name": "Group 1",
                    "type": "endpointParam",
                    "paramName": "symbol",
                    "defaultValue": "AAPL",
                    "widgetIds": [
                        "nasdaq_earnings_calendar",
                        "nasdaq_company_filings",
                    ],
                },
                {
                    "name": "Group 2",
                    "type": "endpointParam",
                    "paramName": "symbol2",
                    "defaultValue": "AAPL",
                    "widgetIds": [
                        "nasdaq_dividends_calendar",
                        "nasdaq_historical_dividends",
                    ],
                },
            ],
        }

    return app
