#!/usr/bin/env python3
"""
Chapter 7: Python for Next Gen Biologist
Script: ch07_modules_packages.py
Description: Designing modular bioinformatics code, structuring packages,
             namespace separation, and reusable genomics utility libraries.
Usage:
    python ch07_modules_packages.py --seq ATGCGATCGATC
"""

import argparse
import sys

class GenomicsToolkit:
    """Namespace container demonstrating structured module design."""
    
    @staticmethod
    def clean_sequence(raw_seq: str) -> str:
        """Strips whitespace, numbers, and converts to uppercase."""
        return "".join(c for c in raw_seq if c.isalpha()).upper()

    @staticmethod
    def expand_iupac(motif: str) -> list:
        """Expands degenerate IUPAC nucleotide codes into all explicit combinations."""
        iupac_map = {
            'A': ['A'], 'C': ['C'], 'G': ['G'], 'T': ['T'],
            'R': ['A', 'G'], 'Y': ['C', 'T'], 'S': ['G', 'C'], 'W': ['A', 'T'],
            'K': ['G', 'T'], 'M': ['A', 'C'], 'B': ['C', 'G', 'T'],
            'D': ['A', 'G', 'T'], 'H': ['A', 'C', 'T'], 'V': ['A', 'C', 'G'],
            'N': ['A', 'C', 'G', 'T']
        }
        sequences = [""]
        for base in motif.upper():
            candidates = iupac_map.get(base, [base])
            sequences = [prefix + c for prefix in sequences for c in candidates]
        return sequences

    @staticmethod
    def compute_dinucleotide_frequencies(sequence: str) -> dict:
        """Calculates observed frequencies of all 16 dinucleotide combinations (e.g. CpG)."""
        seq = sequence.upper()
        dinucs = {}
        for b1 in "ACGT":
            for b2 in "ACGT":
                dinucs[b1 + b2] = 0
                
        for i in range(len(seq) - 1):
            pair = seq[i:i+2]
            if pair in dinucs:
                dinucs[pair] += 1
        return dinucs

def main():
    parser = argparse.ArgumentParser(description="Chapter 7: Genomics Toolkit Module & Packaging Demo.")
    parser.add_argument("-s", "--seq", help="Input DNA sequence")
    parser.add_argument("-m", "--motif", default="RGYW", help="IUPAC degenerate motif to expand (default: RGYW)")
    args = parser.parse_args()

    seq = args.seq.strip() if args.seq else "ATG CGG CCG 123 ATCGATCGATCG TACG ATCG"
    cleaned = GenomicsToolkit.clean_sequence(seq)
    print(f"Original Raw Sequence : {seq}")
    print(f"Cleaned Sequence ({len(cleaned)} bp) : {cleaned}\n")

    expansions = GenomicsToolkit.expand_iupac(args.motif)
    print(f"Expanded IUPAC Motif '{args.motif}' ({len(expansions)} combinations):")
    print(f"  -> {', '.join(expansions)}\n")

    dinucs = GenomicsToolkit.compute_dinucleotide_frequencies(cleaned)
    cpg_count = dinucs.get("CG", 0)
    print(f"Dinucleotide Profile: CpG count = {cpg_count}")
    top_dinucs = sorted(dinucs.items(), key=lambda x: x[1], reverse=True)[:5]
    print(f"Top 5 Dinucleotides : {top_dinucs}")

if __name__ == "__main__":
    main()
