#!/usr/bin/env python3
"""Check a shortlist evidence record. Never score, rank or select people.

Python 3 standard library. Reads local CSV; performs no network calls.
"""
import argparse
import csv
import datetime as dt
import sys

FIELDS = ['candidate_alias', 'criterion_id', 'brief_version', 'criterion_kind',
          'evidence_state', 'evidence_note', 'source_ref', 'observed_on',
          'clarification_owner', 'next_action', 'reviewer_decision']


def check(rows, brief_version, review_date):
    seen = set()
    results = []
    for row in rows:
        alias, criterion = row['candidate_alias'].strip(), row['criterion_id'].strip()
        issues = []
        if not alias or not criterion:
            issues.append('missing_identity_or_criterion')
        key = (alias, criterion)
        if key in seen:
            issues.append('duplicate_candidate_criterion')
        seen.add(key)
        if row['brief_version'] != brief_version:
            issues.append('brief_version_mismatch')
        if row['criterion_kind'] not in {'essential', 'preference'}:
            issues.append('invalid_criterion_kind')
        state = row['evidence_state']
        if state not in {'evidenced', 'unknown', 'conflicting'}:
            issues.append('invalid_evidence_state')
        if state in {'evidenced', 'conflicting'}:
            if not row['evidence_note'].strip() or not row['source_ref'].strip():
                issues.append('missing_evidence_or_source')
            try:
                if dt.date.fromisoformat(row['observed_on']) > review_date:
                    issues.append('future_observation_date')
            except ValueError:
                issues.append('missing_or_invalid_observation_date')
        if state in {'unknown', 'conflicting'}:
            if not row['clarification_owner'].strip() or not row['next_action'].strip():
                issues.append('unowned_open_question')
            issues.append('unknown_recorded' if state == 'unknown' else 'conflict_recorded')
        if not row['next_action'].strip():
            issues.append('missing_next_action')
        if not row['reviewer_decision'].strip():
            issues.append('missing_human_review_status')
        results.append({'candidate_alias': alias, 'criterion_id': criterion,
                        'record_flags': '|'.join(issues) if issues else 'record_fields_present'})
    return results


def main():
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument('csv_path')
    p.add_argument('--brief-version', required=True)
    p.add_argument('--review-date', required=True, type=dt.date.fromisoformat)
    args = p.parse_args()
    with open(args.csv_path, encoding='utf-8-sig', newline='') as f:
        reader = csv.DictReader(f)
        if reader.fieldnames != FIELDS:
            p.error('CSV header must match the downloadable template, in the same order')
        rows = list(reader)
    if not rows:
        p.error('CSV contains no records')
    if any(None in row or any(v is None for v in row.values()) for row in rows):
        p.error('CSV row length does not match the header')
    writer = csv.DictWriter(sys.stdout, fieldnames=['candidate_alias', 'criterion_id', 'record_flags'], lineterminator='\n')
    writer.writeheader()
    writer.writerows(check(rows, args.brief_version, args.review_date))


if __name__ == '__main__':
    main()
