#!/usr/bin/env python3
"""Source-level evidence for P1 items remediated in v0.38.0-UAT Update 1.

This is not runtime acceptance. It verifies that the intended implementation
paths exist and that the Python tree compiles. Local Django/PostgreSQL UAT is
still required before a QA item can be formally Closed.
"""
from pathlib import Path
import compileall
import sys

ROOT = Path(__file__).resolve().parents[1]
BACKEND = ROOT / "backend"


def text(path):
    return (BACKEND / path).read_text(encoding="utf-8", errors="replace")


def has(path, *needles):
    value = text(path)
    return all(n in value for n in needles)


checks = {
    "QA-014": (ROOT / "QA-014-MODEL-FLOW-AUDIT.md").exists() and "STATIC PASS" in (ROOT / "QA-014-MODEL-FLOW-AUDIT.md").read_text(encoding="utf-8", errors="replace"),
    "QA-017": all((BACKEND / "tests" / name).exists() for name in ["test_attendance_contracts.py", "test_import_validation.py", "test_payroll_policy_contracts.py", "test_payroll_adjustment_contracts.py", "test_release_contracts.py"]) and "manage.py test tests" in (ROOT / "LOCAL-UAT-RUNTIME/tools/run_smoke_tests.ps1").read_text(encoding="utf-8", errors="replace"),
    "QA-081": (ROOT / "DEMO-BACKEND-PARITY-MATRIX.csv").exists() and "Deployment Gate" in (ROOT / "DEMO-BACKEND-PARITY-MATRIX.csv").read_text(encoding="utf-8", errors="replace"),
    "QA-007": has("apps/organization/models.py", "class CompanyPolicy", "salary_day_divisor", "monthly_working_hours") and has("apps/payroll/services.py", "get_effective_policy", "salary_day_divisor"),
    "QA-008": has("apps/employees/forms.py", "CustomFieldDefinition", "custom_", "CustomFieldValue.objects.update_or_create") and has("apps/employees/views.py", "custom_field_list", "custom_field_edit"),
    "QA-010": has("apps/workflow/services.py", "publish_management_notice", "NoticeRecipient.objects.bulk_create") and has("apps/workflow/views.py", "notice_mark_read"),
    "QA-022": has("apps/attendance/services.py", "break_minutes", "gross_minutes - break_minutes"),
    "QA-023": has("apps/leave/services.py", "resubmit_leave_request") and has("apps/attendance/services.py", "resubmit_attendance_adjustment") and has("apps/workflow/services.py", "resubmit_employee_request"),
    "QA-024": has("apps/employees/forms.py", "Date of birth cannot be in the future", "Date of birth must be earlier than the joining date", "Confirmation date cannot be earlier than the joining date"),
    "QA-025": has("apps/payroll/forms.py", "Salary effective-from date cannot be earlier than the employee joining date"),
    "QA-032": has("apps/employees/models.py", "employment_end_date") and has("apps/exits/services.py", "case.employee.employment_end_date = case.final_working_day"),
    "QA-035": has("apps/loans/services.py", "minimum_start", "disbursement_month", "Recovery start month"),
    "QA-038": has("apps/payroll/services.py", "payroll_segregation_required", "payroll preparer cannot review/approve/lock", "payroll reviewer cannot approve"),
    "QA-039": has("apps/exits/models.py", "SUBMITTED", "RETURNED", "REJECTED", "reviewer_note", "submission_count") and has("apps/exits/services.py", "review_final_settlement", "Only a submitted final settlement can be reviewed", "submission_count") and has("templates/exits/case_detail.html", "Correct & Resubmit Settlement", "Latest Reviewer Note"),
    "QA-040": all(has("apps/reports/views.py", n) for n in ["employee_master_csv", "leave_balance_csv", "salary_structure_csv", "variable_pay_csv", "final_settlement_csv", "audit_csv"]),
    "QA-047": has("apps/workflow/forms.py", "ALLOWED_ATTACHMENT_EXTENSIONS", "MAX_ATTACHMENT_BYTES", "clean_attachment"),
    "QA-048": has("apps/accounts/admin_utils.py", "ADMIN_UPDATE", "ADMIN_CREATE", "_audit_values", "Django Admin maintenance action"),
    "QA-049": has("apps/accounts/management/commands/bootstrap_roles.py", "least-privilege", "CHANGE_APPS_BY_ROLE", "perm.codename.startswith(\"view_\")") and not has("apps/accounts/management/commands/bootstrap_roles.py", "perm.codename.startswith(\"delete_\")"),
    "QA-054": has("config/settings.py", "BACKUP_REQUIRE_ENCRYPTION", "BACKUP_ENCRYPTION_PASSWORD") and has("apps/core/management/commands/_dbutils.py", "encrypt_backup_file", "aes-256-cbc", "pbkdf2") and has("apps/core/management/commands/restore_database.py", "decrypt_backup_to"),
    "QA-061": has("apps/leave/services.py", "initialize_leave_year", "carry_forward", "max_carry_forward") and has("apps/leave/views.py", "leave_year_initialize"),
    "QA-063": has("apps/leave/services.py", "cancel_approved_leave", "balance.used", "CANCEL_APPROVED") and has("apps/leave/views.py", "leave_cancel"),
    "QA-066": has("apps/attendance/forms.py", "employee_in_service_on", "Attendance date must fall within the employee service period"),
    "QA-069": has("apps/employees/forms.py", "self.fields.pop(\"status\", None)", "class EmployeeLifecycleForm") and has("apps/employees/views.py", "employee_lifecycle", "Completed exit statuses cannot be changed", "EMPLOYEE_") and has("templates/employees/employee_lifecycle.html", "Controlled Action"),
    "QA-070": has("apps/employees/forms.py", "EmployeeDocumentForm", "ALLOWED_EXTENSIONS", "Employee document cannot exceed 10 MB") and has("apps/employees/views.py", "employee_document_download", "FileResponse"),
    "QA-072": has("apps/payroll/services.py", "PayrollLineItem.objects.bulk_create", "salary_line_items"),
    "QA-073": has("apps/payroll/services.py", "payroll.adjustments.all", "adjustment_earnings", "adjustment_deductions", "PAYROLL_ADJUSTMENT"),
    "QA-074": has("apps/payroll/services.py", "engine_version", "attendance_period_fingerprint", "policy", "salary_segments", "attendance", "overtime", "bonus_rows", "deduction_rows", "payroll_adjustments"),
    "QA-075": has("apps/reports/services.py", "_register_payslip_unicode_fonts", "HRPAY_BANGLA_FONT", "shaping=True", "NotoSansBengali") and has("requirements.txt", "reportlab>=4.4"),
    "QA-077": has("apps/employees/models.py", "class EmployeePaymentAccount", "masked_destination") and has("apps/employees/views.py", "employee_payment_account") and has("apps/reports/views.py", "bank_advice_csv", "EXPORT_BANK_ADVICE"),
    "QA-083": has("templates/employees/employee_detail.html", "Additional / Custom Fields") and has("apps/employees/forms.py", "CustomFieldValue.objects.update_or_create"),
    "QA-084": has("templates/employees/employee_detail.html", "Employee Documents", "Upload Document") and has("apps/employees/views.py", "employee_document_upload", "employee_document_download"),
    "QA-085": has("apps/organization/urls.py", "masters/", "master-edit") and has("apps/organization/views.py", "MASTER_CONFIG", "master_list", "master_edit"),
    "QA-086": has("apps/organization/context_processors.py", "company_branding") and has("templates/base.html", "brand_company"),
}

compile_ok = compileall.compile_dir(str(BACKEND), quiet=1)
failed = [qa for qa, ok in checks.items() if not ok]
print(f"Python compileall: {'PASS' if compile_ok else 'FAIL'}")
for qa, ok in checks.items():
    print(f"{qa}: {'STATIC EVIDENCE PASS' if ok else 'STATIC EVIDENCE FAIL'}")
if failed or not compile_ok:
    print("P1 static verifier failed:", ", ".join(failed) or "compileall")
    sys.exit(1)
print(f"{len(checks)} P1 items have source-level remediation evidence. Runtime/UAT proof is still required.")
