from __future__ import annotations

import uuid
from datetime import datetime, timezone
from typing import Optional

from domain.addresses.user_address import UserAddress
from domain.postcode import Postcode
from infrastructure.csv_s3_client import CsvS3Client
from repositories.user_address.user_address_repository import UserAddressRepository

_ADDRESS_COLUMNS: tuple[str, str, str] = ("Address 1", "Address 2", "Address 3")
_POSTCODE_COLUMN: str = "postcode"
_INTERNAL_REFERENCE_COLUMN: str = "Internal Reference"
_POSTCODE_CLEAN_COLUMN: str = "postcode_clean"


class UserAddressCsvS3Repository(UserAddressRepository):
    def __init__(self, csv_client: CsvS3Client, bucket: str) -> None:
        self._csv_client = csv_client
        self._bucket = bucket

    def load_batch(self, s3_uri: str) -> list[UserAddress]:
        rows = self._csv_client.read_rows(s3_uri)
        if rows and _POSTCODE_COLUMN not in rows[0]:
            raise ValueError(
                f"Input CSV {s3_uri} has no {_POSTCODE_COLUMN!r} column; "
                f"columns present: {sorted(rows[0])}"
            )
        addresses: list[UserAddress] = []
        for row in rows:
            parts = [
                row[col].strip()
                for col in _ADDRESS_COLUMNS
                if col in row and row[col].strip()
            ]
            user_address = ", ".join(parts)
            postcode = row.get(_POSTCODE_COLUMN, "")
            raw_ref = row.get(_INTERNAL_REFERENCE_COLUMN, "").strip()
            internal_reference: Optional[str] = raw_ref or None
            addresses.append(
                UserAddress(
                    user_address=user_address,
                    postcode=Postcode(postcode),
                    internal_reference=internal_reference,
                    source_row=row,
                )
            )
        return addresses

    def save_batch(self, addresses: list[UserAddress], path_prefix: str) -> str:
        rows: list[dict[str, str]] = [
            {**addr.source_row, _POSTCODE_CLEAN_COLUMN: str(addr.postcode)}
            for addr in addresses
        ]

        # TODO: [New Starter Task] file_name generation can be standardised
        # and also easier to read, test for future implementation. Buiild that!
        filename = (
            f"{datetime.now(timezone.utc).isoformat()}_{uuid.uuid4().hex[:8]}.csv"
        )
        key = f"{path_prefix.rstrip('/')}/{filename}"
        return self._csv_client.save_rows(rows, key)
