#!/usr/bin/env python3
import csv
import pathlib
import sys
from collections.abc import Iterable

import click

encodings = ("utf-8-sig", "latin-1")
delimiters = (";", "\t", ",")

target_enc = "utf-8-sig"
target_del = ";"


def try_splitlines(infile: pathlib.Path, encoding: str) -> list[str]:
    try:
        with infile.open("r", encoding=encoding, newline="") as f:
            return f.readlines()
    except Exception as e:
        print(e)
        return []


def try_read(infile: pathlib.Path) -> tuple[str, type[csv.Dialect]]:
    for enc in encodings:
        lines = try_splitlines(infile, enc)
        if not lines:
            continue
        sniffer = csv.Sniffer()
        dialect = None
        for delim in delimiters:
            try:
                dialect = sniffer.sniff("".join(lines), delimiters=delim)
            except csv.Error:
                continue
            break
        if not dialect:
            raise ValueError(f"Could not determine delimiter for {infile}.")
        return (enc, dialect)
    else:
        raise ValueError(f"Could not determine encoding for {infile}")


@click.command
@click.argument("infiles", type=click.Path(exists=True, dir_okay=False, path_type=pathlib.Path), nargs=-1)
def main(infiles: Iterable[pathlib.Path] | None = None) -> None:
    if not infiles:
        print("No input files to convert.")
        return None

    infiles = list(infiles)

    for infile in infiles:
        if infile.stem.endswith("-fixed"):
            print(f"Skipping {infile}...")
            continue

        enc, dialect = try_read(infile)
        print(f"{infile.name}: {enc}({dialect.delimiter!r}) -> ", end="")

        outfile = infile.parent / f"{infile.stem}-fixed{infile.suffix}"
        if enc == target_enc:
            print(f"Re-encoding as {target_enc} to be safe: ", end="")
        with infile.open("r", encoding=enc, newline="") as f:
            content = list(csv.reader(f, dialect=dialect))
        with outfile.open("w", encoding=target_enc, newline="") as f:
            csv.writer(f, delimiter=target_del).writerows(content)
        with outfile.open("r", encoding=target_enc, newline="") as f:
            line_lengths = {len(line) for line in csv.DictReader(f, delimiter=target_del)}
            if not (len(line_lengths) == 1 and next(iter(line_lengths)) > 1):
                print("Fix failed.")
            else:
                print("Fixed.")
        print()
    return None


if __name__ == "__main__":
    sys.exit(main())
