"""Build a validated OmegaTherm CSV; this does not run the prediction model."""
import argparse
import csv
import math
from pathlib import Path
import re

AMINO_ACIDS = set("ACDEFGHIKLMNPQRSTVWY")


def make_mutant(sequence, mutations):
    if not sequence or len(sequence) > 1000 or set(sequence) - AMINO_ACIDS:
        raise ValueError("Use 1-1000 uppercase standard amino-acid residues")
    tokens = mutations.split(";")
    result = list(sequence)
    used = set()
    for token in tokens:
        match = re.fullmatch(r"([ACDEFGHIKLMNPQRSTVWY])([1-9][0-9]*)([ACDEFGHIKLMNPQRSTVWY])", token)
        if match is None:
            raise ValueError(f"Invalid substitution: {token!r}")
        old, position, new = match.groups()
        index = int(position) - 1
        if index >= len(sequence) or sequence[index] != old:
            raise ValueError(f"Wild-type residue or position mismatch: {token}")
        if index in used or old == new:
            raise ValueError(f"Repeated position or unchanged residue: {token}")
        used.add(index)
        result[index] = new
    return "".join(result)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("output", type=Path, help="new CSV path; parent must exist")
    parser.add_argument("--sequence", required=True)
    parser.add_argument("--mutation", action="append", required=True,
                        help="one variant per flag; use semicolons within a variant")
    parser.add_argument("--ph", type=float, required=True)
    parser.add_argument("--temp", type=float, required=True, help="degrees Celsius")
    args = parser.parse_args()
    try:
        if not math.isfinite(args.ph) or not 0 <= args.ph <= 11:
            raise ValueError("pH must be finite and between 0 and 11")
        if not math.isfinite(args.temp) or not 0 <= args.temp <= 120:
            raise ValueError("Temperature must be finite and between 0 and 120 Celsius")
        rows = []
        for number, mutations in enumerate(args.mutation, start=1):
            mutant = make_mutant(args.sequence, mutations)
            rows.append([f"variant_{number}", args.sequence, mutant, args.ph, args.temp])
        with args.output.open("x", encoding="utf-8", newline="") as handle:
            writer = csv.writer(handle, lineterminator="\n")
            writer.writerow(["name", "wt_seq", "mut_seq", "pH", "temp"])
            writer.writerows(rows)
    except (OSError, ValueError) as exc:
        parser.exit(1, f"error: {exc}\n")
    print(f"Wrote {len(rows)} variants to {args.output}")


if __name__ == "__main__":
    main()
