
from __future__ import annotations
import argparse, csv, json, re, zipfile
from pathlib import Path
from .engine import score_text, extract_metadata, plagiarism_suspicion
from .importers import read_any_document, is_potential_input
from .archives import extract_archive
from .auth import load_profile, create_profile, save_profile, verify, may_run_check, may_export_checklist, register_check
from .reports import create_checklist_docx, create_grade_register_docx, create_plagiarism_sheet_docx

VERSION = '4.14.0'


def read_text_any(path, lang='ru'):
    info = read_any_document(path, lang=lang)
    return info['text'], info


def make_json_result(path, meta, result, import_info, out_json):
    data = {'source': str(path), 'metadata': meta, 'import': import_info, 'result': result, 'version': VERSION}
    Path(out_json).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')


def user_profile_from_args(args):
    profile = load_profile(args.profile) if args.profile else None
    if args.register_login:
        profile = create_profile(args.register_login, args.password or '', args.full_name or '', args.phone or '', args.user_email or '', paid=args.paid)
        save_profile(profile, args.profile)
    elif profile and args.password and not verify(profile, args.password):
        raise SystemExit('Authorization failed: wrong password')
    return profile


def run_single(args):
    profile = user_profile_from_args(args)
    if not may_run_check(profile, demo_mode=args.demo):
        raise SystemExit('Demo limit exceeded: three free checks are already used. Unlock paid mode to continue.')
    text, info = read_text_any(args.input, lang=args.lang)
    ideal = read_text_any(args.ideal, lang=args.lang)[0] if args.ideal else ''
    meta = extract_metadata(text, args.input)
    result = score_text(text, ideal, lang=args.lang)
    register_check(profile, args.profile)
    if may_export_checklist(profile, paid_flag=args.paid):
        create_checklist_docx(args.out, meta, result, checker=args.checker, email=args.email, import_info=info)
        print(json.dumps({'out': args.out, 'score100': result['score100'], 'grade5': result['grade5'], 'export_allowed': True}, ensure_ascii=False))
    else:
        out_json = str(Path(args.out).with_suffix('.demo_result.json'))
        make_json_result(args.input, meta, result, info, out_json)
        print(json.dumps({'out': out_json, 'score100': result['score100'], 'grade5': result['grade5'], 'export_allowed': False, 'demo_notice': 'Demo mode: checklist download/export is disabled.'}, ensure_ascii=False))


def collect_input_files(args, out_dir: Path):
    files = []
    if args.batch_archive:
        files += extract_archive(args.batch_archive, out_dir / '_input_unpack')
    if args.input_dir:
        files += [p for p in Path(args.input_dir).rglob('*') if is_potential_input(p)]
    # Filter internal/system files after extraction.
    return [p for p in files if is_potential_input(Path(p)) and not Path(p).name.lower().startswith(('__macosx', '.ds_store'))]


def run_batch(args):
    profile = user_profile_from_args(args)
    out_dir = Path(args.out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)
    files = collect_input_files(args, out_dir)
    ideal = read_text_any(args.ideal, lang=args.lang)[0] if args.ideal else ''
    checklist_dir = out_dir / 'checklists'
    checklist_dir.mkdir(exist_ok=True)
    records = []
    export_allowed = may_export_checklist(profile, paid_flag=args.paid)
    for f in files:
        if not may_run_check(profile, demo_mode=args.demo):
            break
        text, info = read_text_any(f, lang=args.lang)
        if not text.strip():
            continue
        meta = extract_metadata(text, str(f))
        result = score_text(text, ideal, lang=args.lang)
        register_check(profile, args.profile)
        rec = {**meta, **{k: result[k] for k in ['score100','grade5','underwork','surplus','lambda','delta','auth']}, 'source_file': str(f), 'import_method': info.get('method')}
        records.append(rec)
        if export_allowed:
            safe = re.sub(r'[^A-Za-zА-Яа-яЁё0-9_-]+', '_', meta['author'])[:60]
            create_checklist_docx(checklist_dir / f'{safe}_{Path(f).stem}_lambda_checklist.docx', meta, result, checker=args.checker, email=args.email, import_info=info)
    register_path = out_dir / 'KLT_4_14_grade_register.docx'
    if export_allowed:
        create_grade_register_docx(register_path, records, checker=args.checker, email=args.email)
    with open(out_dir / 'batch_summary.csv', 'w', encoding='utf-8', newline='') as fp:
        fields = ['institution','group','author','title','source_file','import_method','score100','grade5','underwork','surplus','lambda','delta','auth']
        wr = csv.DictWriter(fp, fieldnames=fields)
        wr.writeheader(); wr.writerows(records)
    export_path = out_dir / 'lambda_checklists_export.zip'
    if export_allowed:
        with zipfile.ZipFile(export_path, 'w', zipfile.ZIP_DEFLATED) as z:
            for p in checklist_dir.glob('*.docx'):
                z.write(p, 'checklists/' + p.name)
            z.write(register_path, register_path.name)
            z.write(out_dir / 'batch_summary.csv', 'batch_summary.csv')
    print(json.dumps({'works': len(records), 'grade_register': str(register_path) if export_allowed else None, 'export': str(export_path) if export_allowed else None, 'export_allowed': export_allowed}, ensure_ascii=False))


def run_compare(args):
    text_a, info_a = read_text_any(args.compare_a, lang=args.lang)
    text_b, info_b = read_text_any(args.compare_b, lang=args.lang)
    meta_a = extract_metadata(text_a, args.compare_a)
    meta_b = extract_metadata(text_b, args.compare_b)
    suspicion = plagiarism_suspicion(text_a, text_b)
    if args.out:
        create_plagiarism_sheet_docx(args.out, meta_a, meta_b, suspicion, checker=args.checker, email=args.email)
    print(json.dumps({'suspicion': suspicion, 'out': args.out}, ensure_ascii=False))


def main():
    ap = argparse.ArgumentParser(description='KLT 4.14 lambda analyzer: files, archives, demo/paywall, reports')
    ap.add_argument('input', nargs='?')
    ap.add_argument('--lang', default='ru', choices=['ru','en','zh'])
    ap.add_argument('--ideal')
    ap.add_argument('--out', default='KLT_4_14_lambda_checklist.docx')
    ap.add_argument('--checker', default='Проверяющий')
    ap.add_argument('--email', default='')
    ap.add_argument('--batch_archive')
    ap.add_argument('--input_dir')
    ap.add_argument('--out_dir', default='batch_output')
    ap.add_argument('--compare_a')
    ap.add_argument('--compare_b')
    ap.add_argument('--demo', action='store_true')
    ap.add_argument('--paid', action='store_true')
    ap.add_argument('--profile', default='klt414_user_profile.json')
    ap.add_argument('--register_login')
    ap.add_argument('--password')
    ap.add_argument('--full_name')
    ap.add_argument('--phone')
    ap.add_argument('--user_email')
    args = ap.parse_args()
    if args.compare_a and args.compare_b:
        run_compare(args)
    elif args.batch_archive or args.input_dir:
        run_batch(args)
    else:
        if not args.input:
            ap.error('input is required unless batch/archive/compare mode is used')
        run_single(args)


if __name__ == '__main__':
    main()
