import json
import logging
from collections import Counter
from datetime import datetime, timedelta
from typing import Any

import pytz
import tornado
from tornado import httputil
from tornado.web import Application

from core.prometheus_metrics_handler import api_requests_counter
from core.utils import safe_json_dumps

CONTINENTS = ["EU", "NA", "SA", "AS", "AF", "OC", "AN"]
BANDS = ["160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "10m", "6m"]
CONTINENTS_SET = frozenset(CONTINENTS)
BANDS_SET = frozenset(BANDS)


class APIDxStatsHandler(tornado.web.RequestHandler):
    """API request handler for /api/v2/dxstats"""

    def __init__(self, application: "Application", request: httputil.HTTPServerRequest, **kwargs: Any):
        self._spots = None
        self._web_server_metrics = None
        super().__init__(application, request, **kwargs)

    def initialize(self, spots, web_server_metrics):
        self._spots = spots
        self._web_server_metrics = web_server_metrics

    def get(self):
        try:
            self._web_server_metrics["last_api_access_time"] = datetime.now(pytz.UTC)
            self._web_server_metrics["api_access_counter"] += 1
            self._web_server_metrics["status"] = "OK"
            api_requests_counter.inc()

            one_hour_ago = (datetime.now(pytz.UTC) - timedelta(hours=1)).timestamp()
            counts = Counter()

            for key in self._spots.keys():
                spot = self._spots.get(key)
                if spot is None:
                    continue
                if not spot.time or spot.time < one_hour_ago:
                    continue
                if spot.de_continent in CONTINENTS_SET and spot.dx_continent in CONTINENTS_SET and spot.band in BANDS_SET:
                    counts[spot.de_continent, spot.dx_continent, spot.band] += 1

            result = {
                de: {dx: {band: counts[de, dx, band] for band in BANDS} for dx in CONTINENTS}
                for de in CONTINENTS
            }

            self.write(json.dumps(result))
            self.set_status(200)
            self.set_header("Cache-Control", "no-store")
            self.set_header("Content-Type", "application/json")

        except Exception as e:
            logging.error("Exception when handling client request to dx stats API: %s", e, exc_info=True)
            self.write(safe_json_dumps("Error - an internal server error occurred."))
            self.set_status(500)
