from random import shuffle
import spacy
import re
from spacy.training import Example
from spacy.tokens import DocBin
from spacy import displacy
from bs4 import BeautifulSoup

ENTITIES = ["PERSON", "LOC"]

entities_disjunction = '|'.join(ENTITIES)
rgx_entity = re.compile(f"<({entities_disjunction})>(.+?)<\/({entities_disjunction})>")
rgx_tag = re.compile(f"<\/?({entities_disjunction})>")


def multi_re_search(pattern, string):
    while True:
        m = re.search(pattern, string)
        if not m: break
        yield m
        string = string[m.end():]
        

def rm_tags(string_with_tags: str) -> str:
    return re.sub(rgx_tag, "", string_with_tags)
    
def get_entities(string_with_tags: str) -> str:
    entities = multi_re_search(rgx_entity, string_with_tags)

    offset = 0
    for e in entities:
        group = e.group(0)
        tag = re.search(rgx_tag, group).group(1)
        span = e.span()
        
        start = max(0, span[0] + offset)
        end =   max(0, span[1] + offset - len(tag) * 2 - 5)
        
        offset += e.end() - len(tag) * 2 - 5  # last entity len - length of the enclosing tags

        yield start, end, tag
        
import examples as samples

examples = samples.examples

nlp = spacy.load("fr_core_news_lg")

def create_set(nlp, examples, output):
    db = DocBin()
    for text in examples:
        entities = list(get_entities(text))
        
        if not entities:
            continue
        
        text = rm_tags(text)
        doc = nlp(text)
        ents = []
        for start, end, label in entities:
            span = doc.char_span(start, end, label=label)
            ents.append(span)
        doc.ents = ents
        print(ents)
        db.add(doc)
    db.to_disk(output)
            

shuffle(examples)
ntrain = int(0.8 * len(examples))
ndev = len(examples) - ntrain
print(len(examples), "train", ntrain, "dev", ndev)
create_set(nlp, examples[:ntrain], "train.spacy")
create_set(nlp, examples[ndev:], "dev.spacy")


# nlp = spacy.load("./output/model-best")
# doc = nlp("fol. 10 v° et 11 r° Transaction par laquelle il fut convenu que (Pierre) Fromond paierait 8 livres 6 sols parisis pour lods et ventes du plâtre qui était tiré dans une vigne située au territoire de Dives, du côté du gibet qui était en la censive du Cens-Commun, dans laquelle ledit Fromond avait PERSONmis de faire une carrière de plâtre sans le consentement du chapitre et dudit Bouchard (de Brétigny), lequel plâtre ne pourrait être tiré que pendant quatre ans, passé lesquels ledit Fromond serait tenu de replacer et mettre ladite vigne en bon état, etc.")
# displacy.serve(doc, style="ent")
