"""
Utility functions for Vorgaben sanity checking and XML export
"""
import datetime
import xml.etree.ElementTree as ET
import xml.dom.minidom
from django.db.models import Count
from itertools import combinations
from dokumente.models import Vorgabe


def check_vorgabe_conflicts():
    """
    Check for conflicts in Vorgaben.
    
    Main rule: If there are two Vorgaben with the same number, Thema and Dokument,
    their valid_from and valid_to date ranges shouldn't intersect.
    
    Returns:
        list: List of conflict dictionaries
    """
    conflicts = []
    
    # Find Vorgaben with same dokument, thema, and nummer
    duplicate_groups = (
        Vorgabe.objects.values('dokument', 'thema', 'nummer')
        .annotate(count=Count('id'))
        .filter(count__gt=1)
    )
    
    for group in duplicate_groups:
        # Get all Vorgaben in this group
        vorgaben = Vorgabe.objects.filter(
            dokument=group['dokument'],
            thema=group['thema'], 
            nummer=group['nummer']
        )
        
        # Check all pairs for date range intersections
        for vorgabe1, vorgabe2 in combinations(vorgaben, 2):
            if date_ranges_intersect(
                vorgabe1.gueltigkeit_von, vorgabe1.gueltigkeit_bis,
                vorgabe2.gueltigkeit_von, vorgabe2.gueltigkeit_bis
            ):
                conflicts.append({
                    'vorgabe1': vorgabe1,
                    'vorgabe2': vorgabe2,
                    'conflict_type': 'date_range_intersection',
                    'message': f"Vorgaben {vorgabe1.Vorgabennummer()} and {vorgabe2.Vorgabennummer()} "
                              f"have intersecting validity periods"
                })
    
    return conflicts


def date_ranges_intersect(start1, end1, start2, end2):
    """
    Check if two date ranges intersect.
    None end date means open-ended range.
    
    Args:
        start1, start2: Start dates
        end1, end2: End dates (can be None for open-ended)
        
    Returns:
        bool: True if ranges intersect
    """
    # If either start date is None, treat it as invalid case
    if not start1 or not start2:
        return False
        
    # If end date is None, treat it as far future
    end1 = end1 or datetime.date.max
    end2 = end2 or datetime.date.max
    
    # Ranges intersect if start1 <= end2 and start2 <= end1
    return start1 <= end2 and start2 <= end1


def format_conflict_report(conflicts, verbose=False):
    """
    Format conflicts into a readable report.
    
    Args:
        conflicts: List of conflict dictionaries
        verbose: Whether to show detailed information
        
    Returns:
        str: Formatted report
    """
    if not conflicts:
        return "✓ No conflicts found in Vorgaben"
    
    lines = [f"Found {len(conflicts)} conflicts:"]
    
    for i, conflict in enumerate(conflicts, 1):
        lines.append(f"\n{i}. {conflict['message']}")
        
        if verbose:
            v1 = conflict['vorgabe1']
            v2 = conflict['vorgabe2']
            
            lines.append(f"   Vorgabe 1: {v1.Vorgabennummer()}")
            lines.append(f"   Valid from: {v1.gueltigkeit_von} to {v1.gueltigkeit_bis or 'unlimited'}")
            lines.append(f"   Title: {v1.titel}")
            
            lines.append(f"   Vorgabe 2: {v2.Vorgabennummer()}")
            lines.append(f"   Valid from: {v2.gueltigkeit_von} to {v2.gueltigkeit_bis or 'unlimited'}")
            lines.append(f"   Title: {v2.titel}")
        
        # Show the overlapping period
        v1 = conflict['vorgabe1']
        v2 = conflict['vorgabe2']
        overlap_start = max(v1.gueltigkeit_von, v2.gueltigkeit_von)
        overlap_end = min(
            v1.gueltigkeit_bis or datetime.date.max,
            v2.gueltigkeit_bis or datetime.date.max
        )
        
        if overlap_end != datetime.date.max:
            lines.append(f"   Overlap: {overlap_start} to {overlap_end}")
        else:
            lines.append(f"   Overlap starts: {overlap_start} (no end)")

    return "\n".join(lines)


# XML Export utilities

def parse_markdown_table(markdown_content):
    """
    Parse markdown table content and return XML element with <table><header><row><column> structure
    """
    lines = [line.strip() for line in markdown_content.strip().split('\n') if line.strip()]
    if not lines:
        return None

    # Create table element
    table = ET.Element('table')

    # Parse first row as header
    header_row = [cell.strip() for cell in lines[0].split('|') if cell.strip()]
    header = ET.SubElement(table, 'header')
    for cell in header_row:
        column = ET.SubElement(header, 'column')
        column.text = cell

    # Parse remaining rows (skip separator row if it exists)
    for line in lines[2:] if len(lines) > 1 and all(c in '-| ' for c in lines[1]) else lines[1:]:
        # Check if this is a separator row
        if all(c in '-| ' for c in line):
            continue

        row = ET.SubElement(table, 'row')
        row_cells = [cell.strip() for cell in line.split('|') if cell.strip()]
        for cell in row_cells:
            column = ET.SubElement(row, 'column')
            column.text = cell

    return table


def prettify_xml(xml_string):
    """
    Prettify XML string with proper indentation
    """
    dom = xml.dom.minidom.parseString(xml_string)
    return dom.toprettyxml(indent="  ", encoding="UTF-8").decode('utf-8')


def build_dokument_xml_element(dokument, parent_element):
    """
    Build XML element for a single Dokument and append it to parent_element.

    Args:
        dokument: Dokument instance (should be prefetched with related data)
        parent_element: Parent XML element to append to

    Returns:
        The created document element
    """
    doc_element = ET.SubElement(parent_element, 'Vorgabendokument')

    ET.SubElement(doc_element, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else ""
    ET.SubElement(doc_element, 'Nummer').text = dokument.nummer
    ET.SubElement(doc_element, 'Name').text = dokument.name

    autoren_element = ET.SubElement(doc_element, 'Autoren')
    for autor in dokument.autoren.all():
        ET.SubElement(autoren_element, 'Autor').text = autor.name

    pruefende_element = ET.SubElement(doc_element, 'Pruefende')
    for pruefender in dokument.pruefende.all():
        ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name

    gueltigkeit_element = ET.SubElement(doc_element, 'Gueltigkeit')
    ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else ""
    ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None

    ET.SubElement(doc_element, 'SignaturCSO').text = dokument.signatur_cso

    geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order')
    if geltungsbereich_sections:
        geltungsbereich_element = ET.SubElement(doc_element, 'Geltungsbereich')
        for gb in geltungsbereich_sections:
            section_type = gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text"
            if section_type in ('tabelle', 'table'):
                table = parse_markdown_table(gb.inhalt)
                if table is not None:
                    abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt')
                    abschnitt_element.set('typ', section_type)
                    abschnitt_element.append(table)
            else:
                abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt')
                abschnitt_element.set('typ', section_type)
                abschnitt_element.text = gb.inhalt

    einleitung_sections = dokument.einleitung_set.all().order_by('order')
    if einleitung_sections:
        einleitung_element = ET.SubElement(doc_element, 'Einleitung')
        for ei in einleitung_sections:
            section_type = ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text"
            if section_type in ('tabelle', 'table'):
                table = parse_markdown_table(ei.inhalt)
                if table is not None:
                    abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt')
                    abschnitt_element.set('typ', section_type)
                    abschnitt_element.append(table)
            else:
                abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt')
                abschnitt_element.set('typ', section_type)
                abschnitt_element.text = ei.inhalt

    ET.SubElement(doc_element, 'Ziel').text = ""
    ET.SubElement(doc_element, 'Grundlagen').text = ""

    changelog_element = ET.SubElement(doc_element, 'Changelog')
    for cl in dokument.changelog.all().order_by('-datum'):
        entry = ET.SubElement(changelog_element, 'Eintrag')
        ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d")
        autoren = ET.SubElement(entry, 'Autoren')
        for autor in cl.autoren.all():
            ET.SubElement(autoren, 'Autor').text = autor.name
        ET.SubElement(entry, 'Aenderung').text = cl.aenderung

    anhaenge_element = ET.SubElement(doc_element, 'Anhaenge')
    ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge

    ET.SubElement(doc_element, 'Verantwortlich').text = "Information Security Management BIT"
    ET.SubElement(doc_element, 'Klassifizierung').text = ""

    glossar_element = ET.SubElement(doc_element, 'Glossar')

    vorgaben_element = ET.SubElement(doc_element, 'Vorgaben')

    for vorgabe in dokument.vorgaben.all().order_by('order'):
        vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe')

        ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer)
        ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel
        ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else ""

        kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order')
        if kurztext_sections:
            kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext')
            for kt in kurztext_sections:
                section_type = kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text"
                if section_type in ('tabelle', 'table'):
                    table = parse_markdown_table(kt.inhalt)
                    if table is not None:
                        abschnitt = ET.SubElement(kurztext_element, 'Abschnitt')
                        abschnitt.set('typ', section_type)
                        abschnitt.append(table)
                else:
                    abschnitt = ET.SubElement(kurztext_element, 'Abschnitt')
                    abschnitt.set('typ', section_type)
                    abschnitt.text = kt.inhalt

        langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order')
        if langtext_sections:
            langtext_element = ET.SubElement(vorgabe_el, 'Langtext')
            for lt in langtext_sections:
                section_type = lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text"
                if section_type in ('tabelle', 'table'):
                    table = parse_markdown_table(lt.inhalt)
                    if table is not None:
                        abschnitt = ET.SubElement(langtext_element, 'Abschnitt')
                        abschnitt.set('typ', section_type)
                        abschnitt.append(table)
                else:
                    abschnitt = ET.SubElement(langtext_element, 'Abschnitt')
                    abschnitt.set('typ', section_type)
                    abschnitt.text = lt.inhalt

        referenz_element = ET.SubElement(vorgabe_el, 'Referenzen')
        for ref in vorgabe.referenzen.all():
            ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer
            ET.SubElement(referenz_element, 'Referenz').text = ref_text

        vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit')
        ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else ""
        ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None

        checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen')
        for cf in vorgabe.checklistenfragen.all():
            ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage

        stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte')
        for stw in vorgabe.stichworte.all():
            ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort

    return doc_element