#!/usr/bin/env python3
"""
Job Cost Estimator CLI for Australian Tradies

A free, open-source command-line tool that helps tradies (electricians, plumbers, HVAC)
quickly estimate job costs for common tasks. Runs locally, needs no internet,
and outputs professional cost estimates to stdout.

Usage:
    python job_cost_estimator.py --trade electrical --room-size 20 --materials copper --labour-hours 4
    python job_cost_estimator.py --trade plumbing --room-size 15 --materials pvc --labour-hours 2
    python job_cost_estimator.py --trade hvac --room-size 50 --materials ducted --labour-hours 8
"""

import argparse
import json
import sys
from datetime import datetime
from dataclasses import dataclass
from typing import Optional


# Material costs per unit (AUD) - based on typical Australian market rates
MATERIAL_COSTS = {
    "electrical": {
        "copper": 85.00,      # per metre
        "aluminium": 45.00,   # per metre
        "pvc": 12.00,         # per metre
        "conduit": 8.00,      # per metre
        "cabling": 3.50,      # per metre
        "switches": 25.00,    # per unit
        "sockets": 20.00,     # per unit
        "lighting": 45.00,    # per unit
    },
    "plumbing": {
        "copper": 75.00,      # per metre
        "pvc": 15.00,         # per metre
        "pex": 25.00,         # per metre
        "fittings": 12.00,    # per unit
        "valves": 35.00,      # per unit
        "fixtures": 85.00,    # per unit
    },
    "hvac": {
        "ducted": 120.00,     # per metre
        "split": 850.00,      # per unit
        "ducting": 35.00,     # per metre
        "insulation": 18.00,  # per square metre
        "thermostat": 150.00, # per unit
    },
}

# Labour rates per hour (AUD) - typical Australian tradie rates
LABOUR_RATES = {
    "electrical": 85.00,      # per hour
    "plumbing": 80.00,        # per hour
    "hvac": 90.00,            # per hour
}

# Base call-out fee (AUD)
CALL_OUT_FEE = 75.00

# GST rate (10%)
GST_RATE = 0.10


@dataclass
class CostEstimate:
    """Holds a complete job cost estimate."""
    trade: str
    room_size: float
    materials: str
    labour_hours: float
    material_cost: float
    labour_cost: float
    call_out: float
    subtotal: float
    gst: float
    total: float
    timestamp: str

    def to_dict(self):
        return {
            "trade": self.trade,
            "room_size_sqm": self.room_size,
            "materials": self.materials,
            "labour_hours": self.labour_hours,
            "material_cost_aud": round(self.material_cost, 2),
            "labour_cost_aud": round(self.labour_cost, 2),
            "call_out_fee_aud": round(self.call_out, 2),
            "subtotal_aud": round(self.subtotal, 2),
            "gst_aud": round(self.gst, 2),
            "total_aud": round(self.total, 2),
            "timestamp": self.timestamp,
        }

    def format_text(self):
        """Format as human-readable text output."""
        lines = [
            "=" * 50,
            "JOB COST ESTIMATE",
            "=" * 50,
            f"Trade: {self.trade.upper()}",
            f"Date: {self.timestamp}",
            "",
            "JOB DETAILS",
            "-" * 50,
            f"Room Size: {self.room_size} sqm",
            f"Materials: {self.materials}",
            f"Estimated Labour: {self.labour_hours} hours",
            "",
            "COST BREAKDOWN",
            "-" * 50,
            f"Materials (${self.material_cost:.2f}/unit x {self.room_size} units): ${self.material_cost * self.room_size:.2f}",
            f"Labour (${self.labour_cost:.2f}/hr x {self.labour_hours} hr): ${self.labour_hours * self.labour_cost:.2f}",
            f"Call-out Fee: ${self.call_out:.2f}",
            "",
            f"SUBTOTAL: ${self.subtotal:.2f}",
            f"GST (10%): ${self.gst:.2f}",
            "-" * 50,
            f"TOTAL: ${self.total:.2f}",
            "=" * 50,
            "",
            "NOTE: This is an estimate only. Final costs may vary based on",
            "site conditions, material availability, and actual labour required.",
        ]
        return "\n".join(lines)


def calculate_estimate(
    trade: str,
    room_size: float,
    materials: str,
    labour_hours: float,
) -> Optional[CostEstimate]:
    """
    Calculate a job cost estimate.

    Args:
        trade: One of 'electrical', 'plumbing', 'hvac'
        room_size: Room/job size in square metres
        materials: Material type (e.g., 'copper', 'pvc', 'ducted')
        labour_hours: Estimated labour hours

    Returns:
        CostEstimate or None if trade/material not found
    """
    trade = trade.lower()
    materials = materials.lower()

    # Validate trade
    if trade not in LABOUR_RATES:
        print(f"Error: Unknown trade '{trade}'. Choose from: {', '.join(LABOUR_RATES.keys())}", file=sys.stderr)
        return None

    # Validate materials
    if materials not in MATERIAL_COSTS.get(trade, {}):
        available = list(MATERIAL_COSTS.get(trade, {}).keys())
        print(f"Error: Unknown material '{materials}' for {trade}. Choose from: {', '.join(available)}", file=sys.stderr)
        return None

    # Get rates
    material_rate = MATERIAL_COSTS[trade][materials]
    labour_rate = LABOUR_RATES[trade]

    # Calculate costs
    material_cost = material_rate * room_size
    labour_cost = labour_rate * labour_hours
    call_out = CALL_OUT_FEE
    subtotal = material_cost + labour_cost + call_out
    gst = subtotal * GST_RATE
    total = subtotal + gst

    return CostEstimate(
        trade=trade,
        room_size=room_size,
        materials=materials,
        labour_hours=labour_hours,
        material_cost=material_rate,
        labour_cost=labour_rate,
        call_out=call_out,
        subtotal=subtotal,
        gst=gst,
        total=total,
        timestamp=datetime.now().strftime("%Y-%m-%d %H:%M"),
    )


def main():
    parser = argparse.ArgumentParser(
        description="Job Cost Estimator for Australian Tradies - Free CLI tool",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python job_cost_estimator.py --trade electrical --room-size 20 --materials copper --labour-hours 4
  python job_cost_estimator.py --trade plumbing --room-size 15 --materials pvc --labour-hours 2
  python job_cost_estimator.py --trade hvac --room-size 50 --materials ducted --labour-hours 8

Output formats:
  --format text  Human-readable text (default)
  --format json  JSON output for scripting

This is a free, open-source tool. No accounts required. Runs locally.
""",
    )

    parser.add_argument(
        "--trade", "-t",
        type=str.lower,
        choices=list(LABOUR_RATES),
        required=True,
        help="Trade type: electrical, plumbing, or hvac",
    )
    parser.add_argument(
        "--room-size", "-r",
        type=float,
        required=True,
        help="Room/job size in square metres",
    )
    parser.add_argument(
        "--materials", "-m",
        required=True,
        help="Material type (e.g., copper, pvc, ducted)"
    )
    parser.add_argument(
        "--labour-hours", "-l",
        type=float,
        required=True,
        help="Estimated labour hours"
    )
    parser.add_argument(
        "--format", "-f",
        choices=["text", "json"],
        default="text",
        help="Output format (default: text)"
    )

    args = parser.parse_args()

    estimate = calculate_estimate(
        trade=args.trade,
        room_size=args.room_size,
        materials=args.materials,
        labour_hours=args.labour_hours,
    )

    if estimate is None:
        sys.exit(1)

    if args.format == "json":
        print(json.dumps(estimate.to_dict(), indent=2))
    else:
        print(estimate.format_text())


if __name__ == "__main__":
    main()
