
from __future__ import annotations
from datetime import date
from pathlib import Path
from collections import defaultdict
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

BRAND = 'KLT 4.14'
SITE = 'www.kurpishev.com'
EMAIL = 'me@kurpishev.ru'
TEL = '+789128325861'
AUTHOR = 'Курпишев Иван Борисович'


def set_cell_shading(cell, fill):
    tc_pr = cell._tc.get_or_add_tcPr()
    shd = OxmlElement('w:shd')
    shd.set(qn('w:fill'), fill)
    tc_pr.append(shd)


def set_cell_text(cell, text, bold=False, size=8.7):
    cell.text = ''
    p = cell.paragraphs[0]
    run = p.add_run(str(text))
    run.font.name = 'Times New Roman'
    run.font.size = Pt(size)
    run.bold = bold
    cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER


def style_document(doc):
    sec = doc.sections[0]
    sec.top_margin = Inches(0.42)
    sec.bottom_margin = Inches(0.42)
    sec.left_margin = Inches(0.50)
    sec.right_margin = Inches(0.50)
    styles = doc.styles
    styles['Normal'].font.name = 'Times New Roman'
    styles['Normal'].font.size = Pt(10)
    for h in ['Heading 1', 'Heading 2', 'Title']:
        styles[h].font.name = 'Times New Roman'


def add_title(doc, title, subtitle=None):
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run(title)
    r.bold = True
    r.font.name = 'Times New Roman'
    r.font.size = Pt(15)
    r.font.color.rgb = RGBColor(31, 78, 121)
    if subtitle:
        p2 = doc.add_paragraph()
        p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
        r2 = p2.add_run(subtitle)
        r2.font.name = 'Times New Roman'
        r2.font.size = Pt(8.5)


def add_section(doc, title):
    p = doc.add_paragraph()
    r = p.add_run(title)
    r.bold = True
    r.font.name = 'Times New Roman'
    r.font.size = Pt(10.5)
    r.font.color.rgb = RGBColor(31, 78, 121)


def add_small(doc, text):
    p = doc.add_paragraph()
    r = p.add_run(text)
    r.font.name = 'Times New Roman'
    r.font.size = Pt(8.5)


def add_table(doc, rows, widths=None, font_size=8.3):
    table = doc.add_table(rows=len(rows), cols=len(rows[0]))
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    table.style = 'Table Grid'
    for i, row in enumerate(rows):
        for j, val in enumerate(row):
            cell = table.cell(i, j)
            set_cell_text(cell, val, bold=(i == 0), size=font_size)
            if i == 0:
                set_cell_shading(cell, 'D9EAF7')
            if widths and j < len(widths):
                cell.width = Inches(widths[j])
    return table


def create_checklist_docx(path, meta, result, checker='Проверяющий', email='', date_value=None, import_info=None):
    date_value = date_value or date.today().isoformat()
    import_info = import_info or {}
    doc = Document()
    style_document(doc)
    add_title(doc, f'{BRAND} — итоговый лямбда-чек-лист', f'Kurpishev Lambda Truth | {SITE} | {EMAIL} | {TEL}')
    add_small(doc, f'Автор метода: {AUTHOR}. Статус: демонстрационный и рекомендательный оценочный лист. Не является обязательным для ученика, студента, учителя, преподавателя или образовательной организации.')

    add_section(doc, '1. Паспорт проверки')
    add_table(doc, [
        ['Поле', 'Значение'], ['Дата', date_value], ['Проверяющий', checker], ['E-mail проверяющего', email],
        ['Автор работы', meta.get('author','')], ['Учебное заведение', meta.get('institution','')], ['Класс/группа', meta.get('group','')], ['Работа / файл', meta.get('title','')],
        ['Способ импорта', import_info.get('method','')], ['Исходное расширение', import_info.get('suffix','')], ['Извлечено знаков', import_info.get('chars','')]
    ], widths=[1.75, 5.2])

    add_section(doc, '2. Reпер и расчет')
    add_table(doc, [
        ['U - поле значений', 'I - ведущая идея', 'R - реальное содержание', 'D - достаточное основание'],
        [result['U'], result['I'], result['R'], result['D']]
    ], widths=[1.7, 1.7, 1.7, 1.7])
    add_table(doc, [
        ['Показатель', 'Значение', 'Пояснение'],
        ['lambda', result['lambda'], 'Приближение к гармоническому пределу -1.'],
        ['Delta = |lambda+1|', result['delta'], 'Дефект согласованности.'],
        ['Auth', result['auth'], 'Коэффициент авторизации Reпера.'],
        ['Недоработка', result['underwork'], 'Нехватка фактического, доказательного или композиционного материала.'],
        ['Избыточность', result['surplus'], 'Лишний материал, не относящийся к проблеме работы.']
    ], widths=[1.8, 1.2, 4.0])

    add_section(doc, '3. Критерии оценки по 100-балльной шкале')
    rows = [['Критерий', 'Оценка / 100', 'Комментарий']]
    rows += [[name, val, comment] for name, val, comment in result['criteria']]
    add_table(doc, rows, widths=[2.45, 0.95, 3.5])

    add_section(doc, '4. Итоговые шкалы')
    add_table(doc, [
        ['Шкала', 'Результат', 'Статус'],
        ['100-балльная / ЕГЭ-совместимая', f"{result['score100']} / 100", 'Рекомендательная нормировка; предметный профиль уточняется по актуальным критериям ФИПИ.'],
        ['5-балльная', result['grade5'], 'Плюсы и минусы применяются только в пятибалльной шкале.'],
        ['10-балльная', result['score10'], 'Экспертная шкала.'],
        ['1000-балльная', result['score1000'], 'Исследовательская шкала.'],
        ['100000-балльная', result['score100000'], 'Корпусная шкала.']
    ], widths=[2.15, 1.35, 3.5])

    add_section(doc, '5. Замечания проверяющего / собственная оценка проверяющего')
    add_table(doc, [['1', ''], ['2', ''], ['3', '']], widths=[0.35, 6.55])
    add_small(doc, 'Дата: ____________________    Подпись проверяющего: ____________________    E-mail: ____________________')
    doc.save(path)


def create_plagiarism_sheet_docx(path, meta_a, meta_b, suspicion, checker='Проверяющий', email='', date_value=None):
    date_value = date_value or date.today().isoformat()
    doc = Document()
    style_document(doc)
    add_title(doc, f'{BRAND} — лист подозрения на заимствование', f'{SITE} | {EMAIL} | {TEL}')
    add_small(doc, 'Этот лист не является юридическим заключением о плагиате. Он фиксирует математически рассчитанное подозрение на структурно-содержательное сходство и требует экспертной проверки.')
    add_section(doc, '1. Сравниваемые работы')
    add_table(doc, [['Поле', 'Работа A', 'Работа B'], ['Автор', meta_a.get('author',''), meta_b.get('author','')], ['Файл', meta_a.get('title',''), meta_b.get('title','')], ['Класс/группа', meta_a.get('group',''), meta_b.get('group','')]], widths=[1.4, 2.7, 2.7])
    add_section(doc, '2. Индексы сходства')
    add_table(doc, [['Показатель','Значение'], ['Jaccard 3-грамм', suspicion['ngram3_jaccard']], ['Словарное сходство', suspicion['vocab_jaccard']], ['Соотношение длины', suspicion['length_ratio']], ['Индекс подозрения P', suspicion['suspicion_index']], ['Уровень', suspicion['risk']]], widths=[2.5,4.4])
    add_small(doc, f'Проверяющий: {checker}; e-mail: {email}; дата: {date_value}; подпись: ____________________')
    doc.save(path)


def create_grade_register_docx(path, records, checker='Проверяющий', email='', date_value=None):
    date_value = date_value or date.today().isoformat()
    doc = Document()
    style_document(doc)
    add_title(doc, f'{BRAND} — ведомость оценок', 'Итоговая ведомость по результатам массовой проверки работ')
    add_small(doc, 'Группировка выполняется по учебному заведению и классу/группе. Оценки являются рекомендательными и не заменяют решение педагога или образовательной организации.')
    add_table(doc, [['Поле', 'Значение'], ['Дата ведомости', date_value], ['Проверяющий', checker], ['E-mail проверяющего', email], ['Статус', f'Рекомендательная ведомость {BRAND}']], widths=[2.0, 4.8])

    grouped = defaultdict(list)
    for rec in records:
        grouped[(rec['institution'], rec['group'])].append(rec)

    for (institution, group), items in sorted(grouped.items()):
        add_section(doc, f'Учебное заведение: {institution}')
        add_section(doc, f'Класс / группа: {group}')
        rows = [['№', 'Фамилия / автор', 'Работа / файл', 'Оценка / 100', '5-балльная', 'Недоработка', 'Избыточность']]
        for i, rec in enumerate(sorted(items, key=lambda r: r['author']), 1):
            rows.append([i, rec['author'], rec['title'], rec['score100'], rec['grade5'], rec['underwork'], rec['surplus']])
        add_table(doc, rows, widths=[0.35, 1.55, 1.55, 0.9, 0.8, 0.9, 0.9], font_size=7.8)

    n = len(records)
    avg = round(sum(float(r['score100']) for r in records) / n, 1) if n else 0
    add_section(doc, 'Сводный итог')
    add_table(doc, [['Показатель', 'Значение'], ['Количество работ', n], ['Средний балл / 100', avg], ['Дата', date_value], ['Подпись проверяющего', '____________________________']], widths=[2.4, 4.4])
    add_small(doc, 'Примечание: варианты записи класса/группы типа 7-б, 7б, 7 Б, 7 б нормализуются к 7-Б. Записи вида Группа 105 нормализуются к виду Группа 105.')
    doc.save(path)
