#!/usr/bin/env python3
"""
Generate bicorder.txt from bicorder.json
"""

import json
import argparse
import sys


def center_text(text, width):
    """Center text within a given width"""
    return text.center(width)


def format_gradient_bar(value):
    """
    Format the gradient bar based on value.
    If value is None, show all bars: [|||||||||]
    If value is 0-8, replace that position with #: [|#||||||||]
    """
    if value is None:
        return "[|||||||||]"

    # Ensure value is in valid range
    if not isinstance(value, int) or value < 0 or value > 8:
        return "[|||||||||]"

    bars = list("|||||||||")
    bars[value] = "#"
    return "[" + "".join(bars) + "]"


def format_gradient_line(term_left, term_right, value, left_width, right_width, center_width):
    """
    Format a gradient line with proper spacing.
    Example: "       explicit < [|||||||||] > implicit      "
    """
    bar = format_gradient_bar(value)
    # Right-align the left term, add the bar, then left-align the right term
    line = f"{term_left.rjust(left_width)} < {bar} > {term_right.ljust(right_width)}"
    return center_text(line, center_width)


def format_metadata_field(field_value, field_name):
    """
    Format metadata field - show value if provided, otherwise show field name in brackets
    """
    if field_value is None or field_value == "":
        return f"[{field_name}]"
    return str(field_value)


def generate_bicorder_text(json_data):
    """Generate the formatted bicorder text from JSON data"""
    lines = []

    # First pass: calculate maximum widths for left and right terms
    max_left_width = 0
    max_right_width = 0

    # Check diagnostic gradients
    for diagnostic_set in json_data.get("diagnostic", []):
        for gradient in diagnostic_set.get("gradients", []):
            term_left = gradient.get("term_left", "")
            term_right = gradient.get("term_right", "")
            max_left_width = max(max_left_width, len(term_left))
            max_right_width = max(max_right_width, len(term_right))

    # Check analysis items
    for analysis_item in json_data.get("analysis", []):
        term_left = analysis_item.get("term_left", "")
        term_right = analysis_item.get("term_right", "")
        max_left_width = max(max_left_width, len(term_left))
        max_right_width = max(max_right_width, len(term_right))

    # Calculate the width needed for centering
    # Gradient line format: "{left_term} < [|||||||||] > {right_term}"
    # That's: max_left_width + 3 + 11 + 3 + max_right_width
    gradient_line_width = max_left_width + max_right_width + 17

    # Also check metadata and headers
    metadata = json_data.get("metadata", {})
    max_text_width = max(
        len("Protocol"),
        len("BICORDER"),
        len(format_metadata_field(metadata.get("protocol"), "Protocol")),
        len(format_metadata_field(metadata.get("analyst"), "Analyst")),
        len(format_metadata_field(metadata.get("standpoint"), "Standpoint")),
        len(format_metadata_field(metadata.get("timestamp"), "Timestamp")),
        len("ANALYSIS")
    )

    # Check diagnostic set names
    for diagnostic_set in json_data.get("diagnostic", []):
        set_name = diagnostic_set.get("set_name", "").upper()
        max_text_width = max(max_text_width, len(set_name))

    # Use the maximum of gradient line width and text width
    center_width = max(gradient_line_width, max_text_width)

    # Header
    lines.append(center_text("Protocol", center_width))
    lines.append(center_text("BICORDER", center_width))
    lines.append("")

    # Metadata section
    lines.append(center_text(format_metadata_field(metadata.get("protocol"), "Protocol"), center_width))
    lines.append(center_text(format_metadata_field(metadata.get("analyst"), "Analyst"), center_width))
    lines.append(center_text(format_metadata_field(metadata.get("standpoint"), "Standpoint"), center_width))
    lines.append(center_text(format_metadata_field(metadata.get("timestamp"), "Timestamp"), center_width))
    lines.append("")

    # Diagnostic sections
    for diagnostic_set in json_data.get("diagnostic", []):
        set_name = diagnostic_set.get("set_name", "").upper()
        lines.append(center_text(set_name, center_width))

        for gradient in diagnostic_set.get("gradients", []):
            term_left = gradient.get("term_left", "")
            term_right = gradient.get("term_right", "")
            value = gradient.get("value")

            lines.append(format_gradient_line(term_left, term_right, value, max_left_width, max_right_width, center_width))

        lines.append("")

    # Analysis section
    lines.append(center_text("ANALYSIS", center_width))
    for analysis_item in json_data.get("analysis", []):
        term_left = analysis_item.get("term_left", "")
        term_right = analysis_item.get("term_right", "")
        value = analysis_item.get("value")

        lines.append(format_gradient_line(term_left, term_right, value, max_left_width, max_right_width, center_width))

    lines.append("")

    return "\n".join(lines)


def main():
    """Main function to read JSON and generate text output"""
    # Set up argument parser
    parser = argparse.ArgumentParser(
        description="Generate formatted bicorder text from JSON input"
    )
    parser.add_argument(
        "input_json",
        help="Path to input JSON file"
    )
    parser.add_argument(
        "output_txt",
        help="Path to output TXT file"
    )

    args = parser.parse_args()

    # Read the JSON file
    try:
        with open(args.input_json, "r") as f:
            data = json.load(f)
    except FileNotFoundError:
        print(f"Error: Input file '{args.input_json}' not found.", file=sys.stderr)
        sys.exit(1)
    except json.JSONDecodeError as e:
        print(f"Error: Invalid JSON in '{args.input_json}': {e}", file=sys.stderr)
        sys.exit(1)

    # Generate the formatted text
    output = generate_bicorder_text(data)

    # Write to output file
    try:
        with open(args.output_txt, "w") as f:
            f.write(output)
        print(f"Successfully generated '{args.output_txt}'")
    except IOError as e:
        print(f"Error: Could not write to '{args.output_txt}': {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
