"""Luthier Logic tools — diagnostics, verification, design validation."""

import itertools
import json
import os
import re

from mentorr.helpers import (
    get_package_data_path,
    get_user_data_dir,
    load_json_data,
    load_reference,
)


def register(mcp):
    """Register all Luthier Logic tools on the given FastMCP instance."""

    @mcp.tool()
    def verify_truth_table(formula: str) -> str:
        """
        Generates a rigorous truth table for a propositional logic formula.
        Supports symbols (P, Q), operators (&, |, ~, ->), and parens.
        Use this to verify logical arguments or validity.
        Example: "(P -> Q) & P -> Q"
        """
        from sympy import symbols, Symbol
        from sympy.logic.boolalg import And, Or, Not, Implies

        fmt_formula = formula.replace("->", ">>").replace("\u2192", ">>")

        tokens = sorted(list(set(re.findall(r'[A-Za-z_][A-Za-z0-9_]*', fmt_formula))))
        vars_list = symbols(' '.join(tokens))
        if len(tokens) == 1:
            vars_list = [vars_list]

        try:
            expr = eval(
                fmt_formula,
                {t: s for t, s in zip(tokens, vars_list)},
                {"And": And, "Or": Or, "Not": Not, "Implies": Implies},
            )
        except Exception as e:
            return f"Error parsing formula: {e}. Please use Python-style syntax: (P >> Q) & P >> Q"

        header = "  " + "  |  ".join(tokens) + "  ||  RESULT"
        width = len(header) + 2
        border = "\u2550" * width
        div = "\u2500" * width

        output = f"{border}\nTRUTH TABLE: {formula}\n{border}\n{header}\n{div}\n"

        results = []
        combinations = list(itertools.product([True, False], repeat=len(tokens)))

        for values in combinations:
            ctx = dict(zip(vars_list, values))
            res = expr.subs(ctx)

            row_str = "  "
            for v in values:
                row_str += "T  " if v else "F  "
                row_str += "|  "

            row_str += "||  " + ("T" if res else "F")
            output += row_str + "\n"
            results.append(bool(res))

        output += border + "\n"

        if all(results):
            classification = "TAUTOLOGY (Valid)"
        elif not any(results):
            classification = "CONTRADICTION (Invalid)"
        else:
            classification = "CONTINGENT (Depends on inputs)"

        output += f"CLASSIFICATION: {classification}\n{border}"
        return output

    @mcp.tool()
    def diagnose(symptom_description: str) -> str:
        """
        Diagnose a guitar issue (buzz, intonation, dead spot) using logic verification.
        Input: "buzz on open strings" or "sharp at 12th fret".
        """
        from mentorr.diagnostic_engine import DiagnosticEngine

        engine = DiagnosticEngine()
        symptom = symptom_description.lower()

        active_symptoms = []
        ref_file = ""
        skill = "luthier-diagnostics"

        if "buzz" in symptom:
            ref_file = "fret-buzz-tree.md"
            if "open" in symptom:
                active_symptoms.append("Buzz_Open")
            elif "12" in symptom or "high" in symptom:
                active_symptoms.append("Buzz_High")
            elif "middle" in symptom or "5" in symptom:
                active_symptoms.append("Buzz_Middle")
            else:
                active_symptoms.append("Buzz_All")

        elif "sharp" in symptom or "flat" in symptom:
            ref_file = "intonation-tree.md"
            if "12" in symptom:
                if "sharp" in symptom:
                    active_symptoms.append("Sharp_12th")
                else:
                    active_symptoms.append("Flat_12th")
            elif "1st" in symptom or "first" in symptom:
                active_symptoms.append("Sharp_1st")
            else:
                active_symptoms.append("Sharp_All")

        elif "dead" in symptom or "wolf" in symptom:
            ref_file = "dead-spots.md"
            if "g string" in symptom or "7th" in symptom:
                active_symptoms.append("Dead_Spot_G")
            elif "wolf" in symptom:
                active_symptoms.append("Wolf_Tone")
            else:
                active_symptoms.append("Dead_Spot_Random")

        if not active_symptoms:
            return "Could not map symptoms to logic symbols. Try 'buzz on open string' or 'sharp at 12th'."

        ref_path = get_package_data_path("references", skill, ref_file)
        engine.load_rules_from_markdown(str(ref_path))

        possible_causes = engine.diagnose(active_symptoms)

        ref_text = load_reference(skill, ref_file)

        result = "--- Diagnostic Logic Result ---\n"
        result += f"Detected Symptoms: {', '.join(active_symptoms)}\n"

        if possible_causes:
            result += f"LOGICAL CAUSES: {', '.join(possible_causes)}\n"
            result += "\n(See reference below for remediation steps)\n"
        else:
            result += "No specific logic rule triggered. Checking general reference...\n"

        return result + "\n" + ref_text

    @mcp.tool()
    def recommend_wood(goal: str) -> str:
        """
        Suggests tonewoods based on a tonal goal and checks availability in inventory.
        """
        woods = load_json_data("wood-properties", "wood_database.json")
        goal_lower = goal.lower()

        matches = []
        for wood in woods:
            if goal_lower in wood.get("tone", "").lower() or goal_lower in wood.get("species", "").lower():
                matches.append(wood)

        if not matches:
            return f"No direct matches for '{goal}'. Try 'warm', 'bright', 'scooped'."

        inventory_path = get_user_data_dir() / "processed" / "master_inventory.csv"

        result = f"Wood Recommendations for '{goal}':\n"
        for w in matches:
            in_stock = "Check Master Sheet"
            if inventory_path.exists():
                content = inventory_path.read_text(encoding="utf-8", errors="ignore").lower()
                if w["species"].lower() in content:
                    in_stock = "YES (In Stock or for sale)"
                else:
                    in_stock = "NO (Not in inventory)"

            result += f"- {w['species']} ({w['category']}): {w['tone']}\n"
            result += f"  Availability: {in_stock}\n"

        return result

    @mcp.tool()
    def verify_design(project_name: str) -> str:
        """
        Verifies a project design against common lutherie constraints.
        Checks if wood choices and measurements saved in project specs are logical.
        """
        projects_dir = get_user_data_dir() / "projects"
        spec_path = projects_dir / f"{project_name.replace(' ', '_').lower()}.txt"
        if not spec_path.exists():
            return f"Specs for {project_name} not found. Use 'save_project_specs' first."

        specs = spec_path.read_text(encoding="utf-8").lower()

        report = f"--- Design Verification: {project_name} ---\n"
        warnings = []

        if "cedar" in specs and ("medium" in specs or "0.013" in specs):
            warnings.append("RISK: Cedar tops are fragile. Medium strings may cause structural failure/bridge lift.")

        if "24" in specs and "open d" in specs:
            warnings.append("NOTE: 24 inch scale with Open D tuning will have very low tension. Consider heavier strings.")

        if not warnings:
            report += "No major structural risks detected based on standard rules.\n"
        else:
            for w in warnings:
                report += f" [!] {w}\n"

        return report

    @mcp.tool()
    def explain_rule(rule_keyword: str) -> str:
        """
        Explains the logic/physics behind a lutherie 'Rule of Thumb'.
        Input: 'scarf joint', 'bridge mass', 'relief', 'grain orientation'.
        """
        explanations = {
            "scarf joint": "Increases headstock strength by ensuring grain runs parallel to the headstock face, preventing 'short grain' breaks common in one-piece necks.",
            "bridge mass": "Higher mass increases sustain but reduces volume/responsiveness. Somogyi argues for lighter bridges to increase monopole efficiency.",
            "relief": "Intentional concave curve in the neck to allow string vibration amplitude without hitting frets in the middle of the neck.",
            "quartersawn": "Ensures maximum stiffness-to-weight ratio and minimum movement (expansion/contraction) across the width of the board.",
        }

        key = rule_keyword.lower()
        if key in explanations:
            return f"RULE: {rule_keyword.title()}\nEXPLANATION: {explanations[key]}"

        return f"I don't have a formalized rule for '{rule_keyword}' yet. Try 'bridge mass' or 'scarf joint'."
