#!/usr/bin/env python3
"""Password policy audit for authorized systems.

This script evaluates a consent-based password sample or password reset intake
export. It does not crack hashes, bypass authentication, or attempt logins.
"""

from __future__ import annotations

import argparse
import csv
import hashlib
from getpass import getpass
from pathlib import Path

COMMON_PASSWORD_SHA256 = {
    hashlib.sha256(value.encode()).hexdigest()
    for value in ["password", "Password1", "Password123", "admin123", "qwerty123", "letmein"]
}


def score_password(password: str) -> list[str]:
    issues: list[str] = []
    if len(password) < 14:
        issues.append("shorter_than_14")
    if password.lower() == password or password.upper() == password:
        issues.append("missing_case_mix")
    if not any(char.isdigit() for char in password):
        issues.append("missing_digit")
    if not any(not char.isalnum() for char in password):
        issues.append("missing_symbol")
    if hashlib.sha256(password.encode()).hexdigest() in COMMON_PASSWORD_SHA256:
        issues.append("known_common_password")
    return issues


def audit_csv(path: Path) -> None:
    with path.open("r", encoding="utf-8", newline="") as handle:
        reader = csv.DictReader(handle)
        if "account" not in reader.fieldnames or "password" not in reader.fieldnames:
            raise SystemExit("CSV must contain account,password columns from an authorized export")
        for row in reader:
            issues = score_password(row["password"])
            print(f"{row['account']}: {'PASS' if not issues else ','.join(issues)}")


def main() -> int:
    parser = argparse.ArgumentParser(description="Assess password quality for authorized accounts.")
    parser.add_argument("--csv", type=Path, help="Authorized CSV with account,password columns")
    parser.add_argument("--interactive", action="store_true", help="Score one password without echoing it")
    args = parser.parse_args()
    if args.csv:
        audit_csv(args.csv)
    elif args.interactive:
        issues = score_password(getpass("Password to score: "))
        print("PASS" if not issues else "Issues: " + ", ".join(issues))
    else:
        raise SystemExit("Use --csv or --interactive")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
