"""GIAS Singer tap — extracts bulk establishment CSV from GIAS API."""

from __future__ import annotations

from datetime import date, timedelta

from singer_sdk import Stream, Tap
from singer_sdk import typing as th

GIAS_URL_TEMPLATE = (
    "https://ea-edubase-api-prod.azurewebsites.net"
    "/edubase/downloads/public/edubasealldata{date}.csv"
)

GIAS_LINKS_URL_TEMPLATE = (
    "https://ea-edubase-api-prod.azurewebsites.net"
    "/edubase/downloads/public/links_edubasealldata{date}.csv"
)


class GIASEstablishmentsStream(Stream):
    """Stream: GIAS establishments (one row per URN)."""

    name = "gias_establishments"
    primary_keys = ["URN"]
    replication_key = None

    # All columns used by dbt staging models must be declared here —
    # target-postgres only persists columns present in the Singer schema.
    # All non-PK columns are StringType; dbt handles type casting.
    schema = th.PropertiesList(
        th.Property("URN", th.IntegerType, required=True),
        th.Property("EstablishmentName", th.StringType),
        th.Property("TypeOfEstablishment (code)", th.StringType),
        th.Property("TypeOfEstablishment (name)", th.StringType),
        th.Property("PhaseOfEducation (code)", th.StringType),
        th.Property("PhaseOfEducation (name)", th.StringType),
        th.Property("OfficialSixthForm (code)", th.StringType),
        th.Property("OfficialSixthForm (name)", th.StringType),
        th.Property("LA (code)", th.StringType),
        th.Property("LA (name)", th.StringType),
        th.Property("EstablishmentNumber", th.StringType),
        th.Property("EstablishmentStatus (code)", th.StringType),
        th.Property("EstablishmentStatus (name)", th.StringType),
        th.Property("Postcode", th.StringType),
        th.Property("Gender (name)", th.StringType),
        th.Property("ReligiousCharacter (code)", th.StringType),
        th.Property("ReligiousCharacter (name)", th.StringType),
        th.Property("AdmissionsPolicy (code)", th.StringType),
        th.Property("AdmissionsPolicy (name)", th.StringType),
        th.Property("SchoolCapacity", th.StringType),
        th.Property("NumberOfPupils", th.StringType),
        th.Property("HeadTitle (name)", th.StringType),
        th.Property("HeadFirstName", th.StringType),
        th.Property("HeadLastName", th.StringType),
        th.Property("TelephoneNum", th.StringType),
        th.Property("SchoolWebsite", th.StringType),
        th.Property("Street", th.StringType),
        th.Property("Locality", th.StringType),
        th.Property("Town", th.StringType),
        th.Property("County (name)", th.StringType),
        th.Property("OpenDate", th.StringType),
        th.Property("CloseDate", th.StringType),
        th.Property("Trusts (name)", th.StringType),
        th.Property("Trusts (code)", th.StringType),
        th.Property("UrbanRural (name)", th.StringType),
        th.Property("ParliamentaryConstituency (name)", th.StringType),
        th.Property("NurseryProvision (name)", th.StringType),
        th.Property("Easting", th.StringType),
        th.Property("Northing", th.StringType),
        th.Property("StatutoryLowAge", th.StringType),
        th.Property("StatutoryHighAge", th.StringType),
    ).to_dict()

    def get_records(self, context):
        """Download GIAS CSV and yield rows."""
        import io

        import pandas as pd
        import requests

        today = date.today()
        url = GIAS_URL_TEMPLATE.format(date=today.strftime("%Y%m%d"))

        self.logger.info("Downloading GIAS bulk CSV: %s", url)
        resp = requests.get(url, timeout=300)

        # GIAS may not have today's file yet — fall back to yesterday
        if resp.status_code == 404:
            yesterday = (today - timedelta(days=1)).strftime("%Y%m%d")
            url = GIAS_URL_TEMPLATE.format(date=yesterday)
            self.logger.info("Today's file not available, trying yesterday: %s", url)
            resp = requests.get(url, timeout=300)

        resp.raise_for_status()

        df = pd.read_csv(
            io.StringIO(resp.text),
            encoding="latin-1",
            dtype=str,
            keep_default_na=False,
        )

        for _, row in df.iterrows():
            record = row.to_dict()
            try:
                record["URN"] = int(record["URN"])
            except (ValueError, KeyError):
                continue
            yield record


class GIASLinksStream(Stream):
    """Stream: GIAS school links (predecessor/successor)."""

    name = "gias_links"
    primary_keys = ["URN", "LinkURN"]
    replication_key = None

    schema = th.PropertiesList(
        th.Property("URN", th.IntegerType, required=True),
        th.Property("LinkURN", th.IntegerType, required=True),
        th.Property("LinkType", th.StringType),
        th.Property("LinkEstablishedDate", th.StringType),
    ).to_dict()

    def get_records(self, context):
        """Download GIAS links CSV and yield rows."""
        import io

        import pandas as pd
        import requests

        today = date.today()
        url = GIAS_LINKS_URL_TEMPLATE.format(date=today.strftime("%Y%m%d"))

        self.logger.info("Downloading GIAS links CSV: %s", url)
        resp = requests.get(url, timeout=300)

        # Fall back to yesterday if today's file isn't available
        if resp.status_code in (404, 500):
            yesterday = (today - timedelta(days=1)).strftime("%Y%m%d")
            url = GIAS_LINKS_URL_TEMPLATE.format(date=yesterday)
            self.logger.info("Today's links file not available, trying yesterday: %s", url)
            resp = requests.get(url, timeout=300)

        resp.raise_for_status()

        df = pd.read_csv(
            io.StringIO(resp.text),
            encoding="latin-1",
            dtype=str,
            keep_default_na=False,
        )

        for _, row in df.iterrows():
            record = row.to_dict()
            try:
                record["URN"] = int(record["URN"])
                record["LinkURN"] = int(record["LinkURN"])
            except (ValueError, KeyError):
                continue
            yield record


class TapUKGIAS(Tap):
    """Singer tap for UK GIAS data."""

    name = "tap-uk-gias"

    config_jsonschema = th.PropertiesList(
        th.Property(
            "download_url",
            th.StringType,
            description="Override GIAS CSV download URL",
        ),
    ).to_dict()

    def discover_streams(self):
        return [
            GIASEstablishmentsStream(self),
            GIASLinksStream(self),
        ]


if __name__ == "__main__":
    TapUKGIAS.cli()
