from pathlib import Path

from django.core.management.base import BaseCommand


FIELD_LENGTHS = [
    2,   # guest_type
    10,  # arrival_date
    50,  # surname
    30,  # name
    1,   # gender
    10,  # birth_date
    9,   # birth_municipality_code
    2,   # birth_province_code
    9,   # country_of_birth_code
    9,   # nationality_code
    9,   # residence_municipality_code
    2,   # residence_province_code
    9,   # country_code
    50,  # address
    5,   # document_type
    20,  # document_number
    9,   # document_issue_place
    10,  # departure_date
    30,  # tourism_type
    30,  # transport_type
    3,   # rooms_occupied
    3,   # rooms_available
    4,   # beds_available
    1,   # city_tax
    10,  # position_code
    1,   # mode
]

LABELS = [
    "guest_type",
    "arrival_date",
    "surname",
    "name",
    "gender",
    "birth_date",
    "birth_municipality_code",
    "birth_province_code",
    "country_of_birth_code",
    "nationality_code",
    "residence_municipality_code",
    "residence_province_code",
    "country_code",
    "address",
    "document_type",
    "document_number",
    "document_issue_place",
    "departure_date",
    "tourism_type",
    "transport_type",
    "rooms_occupied",
    "rooms_available",
    "beds_available",
    "city_tax",
    "position_code",
    "mode",
]

ACCEPTED_TOURISM = {
    "Culturale",
    "Balneare",
    "Congressuale/Affari",
    "Fieristico",
    "Sportivo/Fitness",
    "Scolastico",
    "Religioso",
    "Sociale",
    "Parchi Tematici",
    "Termale/Trattamenti salute",
    "Enogastronomico",
    "Cicloturismo",
    "Escursionistico/Naturalistico",
    "Altro motivo",
    "Non Specificato",
}

ACCEPTED_TRANSPORT = {
    "Auto",
    "Aereo",
    "Aereo+Pullman",
    "Aereo+Navetta/Taxi/Auto",
    "Aereo+Treno",
    "Treno",
    "Pullman",
    "Caravan/Autocaravan",
    "Barca/Nave/Traghetto",
    "Moto",
    "Bicicletta",
    "A piedi",
    "Altro mezzo",
    "Non Specificato",
}


def _split_lines(raw: bytes):
    if b"\r\n" in raw:
        lines = raw.split(b"\r\n")
        if lines and lines[-1] == b"":
            lines = lines[:-1]
        return lines, True, raw.endswith(b"\r\n")
    lines = raw.split(b"\n")
    if lines and lines[-1] == b"":
        lines = lines[:-1]
    return lines, False, False


def _parse_record(line: str):
    fields = {}
    idx = 0
    for label, length in zip(LABELS, FIELD_LENGTHS):
        fields[label] = line[idx:idx + length]
        idx += length
    return fields


class Command(BaseCommand):
    help = "Validate an ISTAT TXT export file against the ROSS1000 v4 fixed-length rules."

    def add_arguments(self, parser):
        parser.add_argument("--file", required=True, help="Path to the TXT file to validate")

    def handle(self, *args, **options):
        path = Path(options["file"])
        if not path.exists():
            self.stderr.write(f"File not found: {path}")
            return

        raw = path.read_bytes()
        lines, used_crlf, trailing_crlf = _split_lines(raw)

        expected_len = sum(FIELD_LENGTHS)
        errors = []

        for idx, line in enumerate(lines, start=1):
            if len(line) != expected_len:
                errors.append((idx, "invalid_length", len(line)))
                continue
            try:
                text = line.decode("ascii")
            except UnicodeDecodeError:
                errors.append((idx, "non_ascii", None))
                text = line.decode("ascii", errors="replace")

            fields = _parse_record(text)

            guest_type = fields["guest_type"].strip()
            mode = fields["mode"].strip()
            position = fields["position_code"].strip()
            departure = fields["departure_date"].strip()

            tourism = fields["tourism_type"].strip()
            transport = fields["transport_type"].strip()

            rooms = fields["rooms_occupied"].strip()
            rooms_avail = fields["rooms_available"].strip()
            beds_avail = fields["beds_available"].strip()

            if not position:
                errors.append((idx, "missing_position_code", None))
            if not mode:
                errors.append((idx, "missing_mode", None))

            if guest_type in {"16", "17", "18"}:
                if not rooms or not rooms_avail or not beds_avail:
                    errors.append((idx, "missing_rooms_beds_for_16_17_18", None))
            if guest_type in {"19", "20"}:
                if rooms or rooms_avail or beds_avail:
                    errors.append((idx, "rooms_beds_should_be_blank_for_19_20", None))

            if mode == "2" and not departure:
                errors.append((idx, "missing_departure_for_mode_2", None))

            if tourism and tourism not in ACCEPTED_TOURISM:
                errors.append((idx, "invalid_tourism", tourism))
            if transport and transport not in ACCEPTED_TRANSPORT:
                errors.append((idx, "invalid_transport", transport))

        self.stdout.write(f"Records: {len(lines)}")
        self.stdout.write(f"Uses CRLF: {used_crlf}")
        self.stdout.write(f"Trailing CRLF: {trailing_crlf}")
        self.stdout.write(f"Errors: {len(errors)}")

        if errors:
            self.stdout.write("Sample errors (first 10):")
            for item in errors[:10]:
                self.stdout.write(f"  line {item[0]}: {item[1]} {item[2] or ''}".rstrip())
