#!/usr/bin/env python3
"""DOCX Generator — JvG Consultancy Premium huisstijl deliverables.
Generates consultancy-grade Word documents from AI markdown output.
Golden Standard: Arcadis / Big4 niveau.
"""

import json
import re
from datetime import datetime
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml

# Branding constants
PRIMARY = RGBColor(0x00, 0x33, 0x66)
ACCENT = RGBColor(0x4E, 0xCD, 0xC4)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK = RGBColor(0x1F, 0x29, 0x37)
DARK_SECONDARY = RGBColor(0x37, 0x41, 0x51)
GREY = RGBColor(0xAD, 0xB5, 0xBD)
GREY_LIGHT = RGBColor(0x6C, 0x75, 0x7D)
CALLOUT_YELLOW = 'FFF8E1'
CALLOUT_BORDER = 'FFB800'
FONT_BODY = 'Calibri'
FONT_HEADING = 'Calibri'


def set_cell_shading(cell, color_hex):
    shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="{color_hex}"/>')
    cell._tc.get_or_add_tcPr().append(shading)


def set_cell_borders(cell, color='DEE2E6', size='4'):
    """Set thin borders on all sides of a cell."""
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    borders = parse_xml(
        f'<w:tcBorders {nsdecls("w")}>'
        f'  <w:top w:val="single" w:sz="{size}" w:space="0" w:color="{color}"/>'
        f'  <w:left w:val="single" w:sz="{size}" w:space="0" w:color="{color}"/>'
        f'  <w:bottom w:val="single" w:sz="{size}" w:space="0" w:color="{color}"/>'
        f'  <w:right w:val="single" w:sz="{size}" w:space="0" w:color="{color}"/>'
        f'</w:tcBorders>'
    )
    tcPr.append(borders)


def set_cell_padding(cell, top=80, bottom=80, left=80, right=80):
    """Set cell padding in twentieths of a point (8pt = 160 twips)."""
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    margins = parse_xml(
        f'<w:tcMar {nsdecls("w")}>'
        f'  <w:top w:w="{top}" w:type="dxa"/>'
        f'  <w:start w:w="{left}" w:type="dxa"/>'
        f'  <w:bottom w:w="{bottom}" w:type="dxa"/>'
        f'  <w:end w:w="{right}" w:type="dxa"/>'
        f'</w:tcMar>'
    )
    tcPr.append(margins)


def add_styled_table(doc, headers, rows, col_widths=None):
    table = doc.add_table(rows=1 + len(rows), cols=len(headers))
    table.alignment = WD_TABLE_ALIGNMENT.CENTER

    # Header row
    for i, h in enumerate(headers):
        cell = table.rows[0].cells[i]
        cell.text = ''
        set_cell_shading(cell, '003366')
        set_cell_borders(cell, '003366', '6')
        set_cell_padding(cell, 100, 100, 100, 100)
        p = cell.paragraphs[0]
        p.alignment = WD_ALIGN_PARAGRAPH.LEFT
        run = p.add_run(h)
        run.font.color.rgb = WHITE
        run.font.bold = True
        run.font.size = Pt(10)
        run.font.name = FONT_BODY
        cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER

    # Data rows
    for ri, row in enumerate(rows):
        for ci, val in enumerate(row):
            cell = table.rows[ri + 1].cells[ci]
            cell.text = ''
            set_cell_borders(cell, 'DEE2E6', '4')
            set_cell_padding(cell, 80, 80, 100, 100)

            # First column gets subtle background
            if ci == 0:
                set_cell_shading(cell, 'F0F4F8')
            elif ri % 2 == 1:
                set_cell_shading(cell, 'F8FAFB')

            p = cell.paragraphs[0]
            run = p.add_run(str(val))
            run.font.size = Pt(10)
            run.font.name = FONT_BODY
            run.font.color.rgb = DARK_SECONDARY
            cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER

    if col_widths:
        for i, w in enumerate(col_widths):
            for row in table.rows:
                row.cells[i].width = Cm(w)

    doc.add_paragraph('')
    return table


def add_callout_box(doc, text, prefix='⚠ Belangrijk'):
    """Add a callout box with yellow background and left border."""
    # Create a single-cell table for the callout
    table = doc.add_table(rows=1, cols=1)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    cell = table.rows[0].cells[0]
    set_cell_shading(cell, CALLOUT_YELLOW)

    # Left border accent
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    borders = parse_xml(
        f'<w:tcBorders {nsdecls("w")}>'
        f'  <w:top w:val="single" w:sz="4" w:space="0" w:color="{CALLOUT_BORDER}"/>'
        f'  <w:left w:val="single" w:sz="24" w:space="0" w:color="{CALLOUT_BORDER}"/>'
        f'  <w:bottom w:val="single" w:sz="4" w:space="0" w:color="{CALLOUT_BORDER}"/>'
        f'  <w:right w:val="single" w:sz="4" w:space="0" w:color="{CALLOUT_BORDER}"/>'
        f'</w:tcBorders>'
    )
    tcPr.append(borders)
    set_cell_padding(cell, 80, 80, 140, 100)

    p = cell.paragraphs[0]
    run_prefix = p.add_run(prefix + '  ')
    run_prefix.font.bold = True
    run_prefix.font.size = Pt(10)
    run_prefix.font.color.rgb = RGBColor(0x8B, 0x6D, 0x00)
    run_prefix.font.name = FONT_BODY
    run_text = p.add_run(text)
    run_text.font.size = Pt(10)
    run_text.font.color.rgb = DARK_SECONDARY
    run_text.font.name = FONT_BODY

    doc.add_paragraph('')


def strip_markdown_code_blocks(text):
    text = re.sub(r'```\w*\n?', '', text)
    return text


def clean_line(line):
    line = re.sub(r'\*\*(.+?)\*\*', r'\1', line)
    line = re.sub(r'\*(.+?)\*', r'\1', line)
    line = re.sub(r'`(.+?)`', r'\1', line)
    line = re.sub(r'^#{1,6}\s+', '', line)
    line = re.sub(r'^---+$', '', line)
    line = re.sub(r'^> ', '', line)
    return line.strip()


def parse_ai_response(text):
    """Parse AI markdown into structured sections with typed content blocks."""
    text = strip_markdown_code_blocks(text)
    sections = []
    current = {'title': '', 'content': [], 'level': 1}

    for line in text.split('\n'):
        stripped = line.strip()
        if not stripped:
            current['content'].append({'type': 'blank'})
            continue

        # Headings
        m = re.match(r'^(#{1,3})\s+(.+)', stripped)
        if m:
            if current['title'] or any(c['type'] != 'blank' for c in current['content']):
                sections.append(current)
            level = len(m.group(1))
            current = {'title': m.group(2).strip(), 'content': [], 'level': level}
            continue

        # Table rows
        if stripped.startswith('|') and '|' in stripped[1:]:
            cells = [c.strip() for c in stripped.split('|')[1:-1]]
            if not cells or all(set(c) <= {'-', '', ' '} for c in cells):
                continue
            if not current['content'] or current['content'][-1].get('type') != 'table':
                current['content'].append({'type': 'table', 'headers': [], 'rows': []})
            tbl = current['content'][-1]
            if not tbl['headers']:
                tbl['headers'] = cells
            else:
                tbl['rows'].append(cells)
            continue

        # Callout detection: > ⚠ or > Belangrijk or > Let op
        callout_m = re.match(r'^>\s*(⚠|Belangrijk|Let op)[:\s]*(.*)', stripped, re.IGNORECASE)
        if callout_m:
            prefix = '⚠ Belangrijk' if callout_m.group(1) == '⚠' else callout_m.group(1).capitalize()
            current['content'].append({'type': 'callout', 'text': callout_m.group(2).strip(), 'prefix': prefix})
            continue

        # Bullet lists
        if re.match(r'^[-*]\s+', stripped):
            text = clean_line(stripped)
            if text:
                current['content'].append({'type': 'bullet', 'text': text})
            continue

        # Numbered lists
        m = re.match(r'^(\d+)\.\s+(.+)', stripped)
        if m:
            text = clean_line(stripped)
            if text:
                current['content'].append({'type': 'numbered', 'text': text})
            continue

        # Regular text
        text = clean_line(stripped)
        if text:
            current['content'].append({'type': 'text', 'text': text})

    if current['title'] or any(c['type'] != 'blank' for c in current['content']):
        sections.append(current)
    return sections


def add_heading_border(paragraph, color_hex='4ECDC4', size='4'):
    """Add a bottom border to a heading paragraph."""
    pPr = paragraph._p.get_or_add_pPr()
    pBdr = parse_xml(
        f'<w:pBdr {nsdecls("w")}>'
        f'  <w:bottom w:val="single" w:sz="{size}" w:space="4" w:color="{color_hex}"/>'
        f'</w:pBdr>'
    )
    pPr.append(pBdr)


def render_content_block(doc, block):
    btype = block.get('type')

    if btype == 'blank':
        return
    elif btype == 'text':
        p = doc.add_paragraph(block['text'])
        p.paragraph_format.space_after = Pt(6)
        p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
        p.paragraph_format.line_spacing = 1.15
        for run in p.runs:
            run.font.name = FONT_BODY
            run.font.size = Pt(11)
            run.font.color.rgb = DARK_SECONDARY
    elif btype == 'bullet':
        p = doc.add_paragraph(style='List Bullet')
        p.clear()
        run = p.add_run(block['text'])
        run.font.name = FONT_BODY
        run.font.size = Pt(11)
        run.font.color.rgb = DARK_SECONDARY
        p.paragraph_format.space_after = Pt(3)
        p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
        p.paragraph_format.line_spacing = 1.15
        # Custom bullet color
        pPr = p._p.get_or_add_pPr()
        numPr = pPr.find(qn('w:numPr'))
        if numPr is not None:
            numPr_parent = numPr.getparent()
            numPr_parent.remove(numPr)
        # Add custom bullet
        numId = '1'
        ilvl = '0'
        numPr_xml = parse_xml(
            f'<w:numPr {nsdecls("w")}>'
            f'  <w:ilvl w:val="{ilvl}"/>'
            f'  <w:numId w:val="{numId}"/>'
            f'</w:numPr>'
        )
        pPr.append(numPr_xml)
    elif btype == 'numbered':
        p = doc.add_paragraph(style='List Number')
        p.clear()
        run = p.add_run(block['text'])
        run.font.name = FONT_BODY
        run.font.size = Pt(11)
        run.font.color.rgb = DARK_SECONDARY
        p.paragraph_format.space_after = Pt(3)
        p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
        p.paragraph_format.line_spacing = 1.15
    elif btype == 'callout':
        add_callout_box(doc, block['text'], block.get('prefix', '⚠ Belangrijk'))
    elif btype == 'table':
        tbl = block
        if tbl.get('headers') and tbl.get('rows'):
            add_styled_table(doc, tbl['headers'], tbl['rows'])


def generate_docx(title, deliv_type, category, intake, ai_text, sources=None):
    """Generate a premium branded DOCX deliverable."""
    doc = Document()

    # ── Default Styles ──
    style = doc.styles['Normal']
    style.font.name = FONT_BODY
    style.font.size = Pt(11)
    style.font.color.rgb = DARK_SECONDARY
    style.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
    style.paragraph_format.line_spacing = 1.15
    style.paragraph_format.space_after = Pt(6)

    for i in range(1, 4):
        hs = doc.styles[f'Heading {i}']
        hs.font.name = FONT_HEADING
        hs.font.color.rgb = PRIMARY
        hs.font.bold = True
        if i == 1:
            hs.font.size = Pt(20)
            hs.paragraph_format.space_before = Pt(24)
            hs.paragraph_format.space_after = Pt(8)
        elif i == 2:
            hs.font.size = Pt(15)
            hs.font.bold = True
            hs.paragraph_format.space_before = Pt(18)
            hs.paragraph_format.space_after = Pt(6)
        else:
            hs.font.size = Pt(12)
            hs.font.bold = False
            hs.font.italic = True
            hs.paragraph_format.space_before = Pt(12)
            hs.paragraph_format.space_after = Pt(4)

    sections_data = parse_ai_response(ai_text)

    # ═══════════════════════════════════════════
    # COVER PAGE
    # ═══════════════════════════════════════════

    # Top color bar (2cm)
    section = doc.sections[0]
    section.top_margin = Cm(2.5)
    section.bottom_margin = Cm(2.5)
    section.left_margin = Cm(2.5)
    section.right_margin = Cm(2.5)

    # Add colored header bar using a table (2cm high)
    bar_table = doc.add_table(rows=1, cols=1)
    bar_table.alignment = WD_TABLE_ALIGNMENT.CENTER
    bar_cell = bar_table.rows[0].cells[0]
    set_cell_shading(bar_cell, '003366')
    bar_cell.text = ''
    # Remove all borders
    tc = bar_cell._tc
    tcPr = tc.get_or_add_tcPr()
    borders = parse_xml(
        f'<w:tcBorders {nsdecls("w")}>'
        f'  <w:top w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        f'  <w:left w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        f'  <w:bottom w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        f'  <w:right w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        f'</w:tcBorders>'
    )
    tcPr.append(borders)
    # Set row height to ~2cm
    tr = bar_table.rows[0]._tr
    trPr = tr.get_or_add_trPr()
    trHeight = parse_xml(f'<w:trHeight {nsdecls("w")} w:val="1134" w:hRule="exact"/>')
    trPr.append(trHeight)
    # Set table width to full page
    tbl = bar_table._tbl
    tblPr = tbl.tblPr if tbl.tblPr is not None else parse_xml(f'<w:tblPr {nsdecls("w")}/>') 
    tblW = parse_xml(f'<w:tblW {nsdecls("w")} w:type="pct" w:w="5000"/>')
    tblPr.append(tblW)

    # Whitespace
    for _ in range(6):
        doc.add_paragraph('')

    # Document type label (small, centered, above title)
    type_labels = {
        'advies': 'ADVIESRAPPORT',
        'procedure': 'PROCEDURE',
        'checklist': 'CHECKLIST',
        'rapport': 'AUDITRAPPORT'
    }
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(type_labels.get(deliv_type, 'RAPPORT'))
    run.font.size = Pt(12)
    run.font.color.rgb = ACCENT
    run.font.bold = True
    run.font.name = FONT_HEADING
    run.font.all_caps = True
    p.paragraph_format.space_after = Pt(4)

    # Main title
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(title)
    run.font.size = Pt(26)
    run.font.bold = True
    run.font.color.rgb = PRIMARY
    run.font.name = FONT_HEADING
    p.paragraph_format.space_after = Pt(6)

    # Accent line UNDER title
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run('━' * 50)
    run.font.color.rgb = ACCENT
    run.font.size = Pt(12)
    p.paragraph_format.space_before = Pt(2)
    p.paragraph_format.space_after = Pt(12)

    # Category subtitle
    if category:
        p = doc.add_paragraph()
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        run = p.add_run(category)
        run.font.size = Pt(14)
        run.font.color.rgb = DARK_SECONDARY
        run.font.name = FONT_BODY
        run.font.italic = True
        p.paragraph_format.space_after = Pt(20)

    # Intake context
    if intake:
        ctx_items = []
        for k, v in intake.items():
            if v:
                label = k.replace('_', ' ').capitalize()
                if isinstance(v, list):
                    v = ', '.join(v)
                ctx_items.append(f'{label}: {v}')
        if ctx_items:
            for item in ctx_items:
                p = doc.add_paragraph()
                p.alignment = WD_ALIGN_PARAGRAPH.CENTER
                run = p.add_run(item)
                run.font.size = Pt(10)
                run.font.color.rgb = GREY_LIGHT
                run.font.name = FONT_BODY
                p.paragraph_format.space_after = Pt(2)

    # Spacer
    for _ in range(3):
        doc.add_paragraph('')

    # Bottom row: version left, date right
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.LEFT
    run = p.add_run('Versie 1.0')
    run.font.size = Pt(10)
    run.font.color.rgb = GREY_LIGHT
    run.font.name = FONT_BODY

    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
    run = p.add_run(datetime.now().strftime('%d %B %Y'))
    run.font.size = Pt(10)
    run.font.color.rgb = GREY_LIGHT
    run.font.name = FONT_BODY

    # Vertrouwelijk
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
    run = p.add_run('Vertrouwelijk')
    run.font.size = Pt(9)
    run.font.color.rgb = GREY
    run.font.name = FONT_BODY
    run.font.italic = True

    doc.add_page_break()

    # ═══════════════════════════════════════════
    # INHOUDSOPGAVE
    # ═══════════════════════════════════════════
    p = doc.add_heading('Inhoudsopgave', level=1)

    # Use a table for two-column TOC with dot leaders
    toc_items = [(sec['title'], sec['level']) for sec in sections_data if sec['title']]
    if toc_items:
        toc_table = doc.add_table(rows=len(toc_items), cols=2)
        toc_table.alignment = WD_TABLE_ALIGNMENT.LEFT
        for idx, (t, lvl) in enumerate(toc_items):
            left_cell = toc_table.rows[idx].cells[0]
            right_cell = toc_table.rows[idx].cells[1]

            # Remove borders
            for cell in [left_cell, right_cell]:
                tc = cell._tc
                tcPr = tc.get_or_add_tcPr()
                borders = parse_xml(
                    f'<w:tcBorders {nsdecls("w")}>'
                    f'  <w:top w:val="none" w:sz="0" w:space="0"/>'
                    f'  <w:left w:val="none" w:sz="0" w:space="0"/>'
                    f'  <w:bottom w:val="none" w:sz="0" w:space="0"/>'
                    f'  <w:right w:val="none" w:sz="0" w:space="0"/>'
                    f'</w:tcBorders>'
                )
                tcPr.append(borders)

            indent = '    ' * (lvl - 1)
            left_cell.text = ''
            p = left_cell.paragraphs[0]
            run = p.add_run(f'{indent}{t}')
            run.font.size = Pt(11)
            run.font.name = FONT_BODY
            if lvl == 1:
                run.font.bold = True
                run.font.color.rgb = PRIMARY
            else:
                run.font.color.rgb = DARK_SECONDARY

            # Right cell: tab stop with dot leader (approximate)
            right_cell.text = ''
            p = right_cell.paragraphs[0]
            p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
            run = p.add_run('.')
            run.font.size = Pt(11)
            run.font.color.rgb = GREY

        # Set column widths
        for row in toc_table.rows:
            row.cells[0].width = Cm(14)
            row.cells[1].width = Cm(2)

    doc.add_page_break()

    # ═══════════════════════════════════════════
    # CONTENT
    # ═══════════════════════════════════════════
    for sec in sections_data:
        if not sec['title'] and not any(c['type'] != 'blank' for c in sec.get('content', [])):
            continue

        if sec['title']:
            level = min(sec['level'], 3)
            heading = doc.add_heading(sec['title'], level=level)

            # Add accent border under Heading 1
            if level == 1:
                add_heading_border(heading, '4ECDC4', '4')

        for block in sec.get('content', []):
            render_content_block(doc, block)

    # ═══════════════════════════════════════════
    # BRONVERMELDING
    # ═══════════════════════════════════════════
    if sources:
        doc.add_page_break()
        doc.add_heading('Bronvermelding', level=1)
        for src in sources:
            p = doc.add_paragraph(src, style='List Bullet')
            p.paragraph_format.space_after = Pt(2)
            for run in p.runs:
                run.font.size = Pt(10)
                run.font.color.rgb = DARK_SECONDARY

    # ═══════════════════════════════════════════
    # DISCLAIMER
    # ═══════════════════════════════════════════
    doc.add_page_break()
    p = doc.add_paragraph()
    run = p.add_run('Disclaimer')
    run.font.size = Pt(14)
    run.font.bold = True
    run.font.color.rgb = PRIMARY
    run.font.name = FONT_HEADING
    p.paragraph_format.space_after = Pt(12)

    disclaimer_text = (
        'Dit document is opgesteld door JvG Consultancy en is uitsluitend bestemd voor de '
        'opdrachtgever. Het document mag niet zonder schriftelijke toestemming worden '
        'vermenigvuldigd of openbaar gemaakt.'
    )
    p = doc.add_paragraph()
    run = p.add_run(disclaimer_text)
    run.font.size = Pt(9)
    run.font.color.rgb = GREY
    run.font.italic = True
    run.font.name = FONT_BODY

    # ═══════════════════════════════════════════
    # FOOTER (all sections)
    # ═══════════════════════════════════════════
    for section in doc.sections:
        section.top_margin = Cm(2.5)
        section.bottom_margin = Cm(2.0)
        section.left_margin = Cm(2.5)
        section.right_margin = Cm(2.5)

        footer = section.footer
        footer.is_linked_to_previous = False
        p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER

        # Left: JvG Consultancy
        run_left = p.add_run('JvG Consultancy — HSEQ Intelligence')
        run_left.font.size = Pt(8)
        run_left.font.color.rgb = GREY
        run_left.font.name = FONT_BODY

        # Center: separator
        run_sep = p.add_run('    —    ')
        run_sep.font.size = Pt(8)
        run_sep.font.color.rgb = GREY

        # Right: Page X van Y
        fldChar1 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
        run_page = p.add_run()
        run_page.font.size = Pt(8)
        run_page.font.color.rgb = GREY
        run_page.font.name = FONT_BODY
        run_page._r.append(fldChar1)

        instrText = parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> PAGE </w:instrText>')
        run_page._r.append(instrText)

        fldChar2 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
        run_page._r.append(fldChar2)

        run_of = p.add_run(' van ')
        run_of.font.size = Pt(8)
        run_of.font.color.rgb = GREY
        run_of.font.name = FONT_BODY

        fldChar3 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
        run_total = p.add_run()
        run_total.font.size = Pt(8)
        run_total.font.color.rgb = GREY
        run_total.font.name = FONT_BODY
        run_total._r.append(fldChar3)

        instrText2 = parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> NUMPAGES </w:instrText>')
        run_total._r.append(instrText2)

        fldChar4 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
        run_total._r.append(fldChar4)

    return doc
