import logging

from flask import Blueprint, Response, jsonify
from flask.views import MethodView

import ckan.plugins.toolkit as tk

from ckanext.tables.generics import AjaxTableMixin, ExportTableMixin
from ckanext.tables.helpers import tables_init_temporary_preview_table
from ckanext.tables.table import TableDefinition

log = logging.getLogger(__name__)

bp = Blueprint("tables", __name__)


class ResourceViewHandler(AjaxTableMixin, ExportTableMixin, MethodView):
    """Handler for resource view AJAX requests."""

    def get_table_for_resource(self, resource_id: str, resource_view_id: str) -> TableDefinition:
        """Get a table definition for a given resource.

        Args:
            resource_id: The resource ID
            resource_view_id: The resource view ID

        Returns:
            A TableDefinition object
        """
        try:
            resource = tk.get_action("resource_show")({"ignore_auth": False}, {"id": resource_id})
        except tk.ObjectNotFound:
            tk.abort(404, tk._("Resource not found"))
        except tk.NotAuthorized:
            tk.abort(403, tk._("Not authorized to view this resource"))

        try:
            resource_view = tk.get_action("resource_view_show")({"ignore_auth": False}, {"id": resource_view_id})
        except tk.ObjectNotFound:
            tk.abort(404, tk._("Resource view not found"))
        except tk.NotAuthorized:
            tk.abort(403, tk._("Not authorized to view this resource"))

        return tables_init_temporary_preview_table(resource, resource_view)

    def get(self, resource_id: str, resource_view_id: str) -> str | Response:
        """Handle AJAX requests for resource view tables.

        Args:
            resource_id: The resource ID
            resource_view_id: The resource view ID

        Returns:
            JSON response with table data or export file
        """
        table = self.get_table_for_resource(resource_id, resource_view_id)

        if exporter_name := tk.request.args.get("exporter"):
            return self._export(table, exporter_name)

        if tk.request.headers.get("X-Requested-With") == "XMLHttpRequest":
            return self._ajax_data(table)

        tk.abort(400, tk._("This endpoint only accepts AJAX requests"))

    def post(self, resource_id: str, resource_view_id: str) -> Response:
        """Handle POST requests for resource view tables (actions, refresh).

        Args:
            resource_id: The resource ID
            resource_view_id: The resource view ID

        Returns:
            JSON response with action result
        """
        table = self.get_table_for_resource(resource_id, resource_view_id)

        row_action = tk.request.form.get("row_action")
        table_action = tk.request.form.get("table_action")
        bulk_action = tk.request.form.get("bulk_action")
        row = tk.request.form.get("row")
        rows = tk.request.form.get("rows")
        refresh = tk.request.form.get("refresh")

        if table_action:
            return self._apply_table_action(table, table_action)
        if row_action:
            return self._apply_row_action(table, row_action, row)
        if bulk_action:
            return self._apply_bulk_action(table, bulk_action, rows)
        if refresh:
            return self._refresh_data(table)

        return jsonify({"success": False, "error": "No action specified"})


bp.add_url_rule(
    "/resource-table-ajax/<resource_id>/<resource_view_id>",
    view_func=ResourceViewHandler.as_view("resource_table_ajax"),
)


class ResourceViewDeferredHandler(MethodView):
    """Renders the full table HTML snippet, called lazily after page load.

    HTMX fires a GET request to this endpoint on page load, so the expensive
    ``tables_init_temporary_preview_table`` call (which fetches remote data to
    discover column names) happens *after* the browser has already rendered the
    page skeleton — avoiding a blank-page experience and production timeouts on
    the initial page request.
    """

    def get(self, resource_id: str, resource_view_id: str) -> str:
        try:
            resource = tk.get_action("resource_show")({"ignore_auth": False}, {"id": resource_id})
            resource_view = tk.get_action("resource_view_show")({"ignore_auth": False}, {"id": resource_view_id})
        except tk.ObjectNotFound:
            return tk.abort(404, tk._("Resource not found"))
        except tk.NotAuthorized:
            return tk.abort(403, tk._("Not authorized to view this resource"))

        try:
            table = tables_init_temporary_preview_table(resource, resource_view)
        except Exception:
            log.exception("Failed to initialize table for resource %s", resource_id)
            tk.abort(500, tk._("Failed to load table. The resource may be unavailable or in an unsupported format."))

        return tk.render(
            "tables/render_table.html",
            extra_vars={"table": table},
        )


bp.add_url_rule(
    "/resource-table-deferred/<resource_id>/<resource_view_id>",
    view_func=ResourceViewDeferredHandler.as_view("resource_table_deferred"),
)
