#!/usr/bin/python3

from appl import db
from appl.models import SpaVerb, EngVerb, Translation, Tense, Person, \
                        Pronoun, Ending, Exception

import re

def initialized():
    v = SpaVerb.query.filter_by(infinitive='terminar').first()
    if v:
        return True
    return False

def db_init():

    if initialized():
        return

    VerbRE = re.compile(r'(\w+)((?:a|e|i)r)$')
    TransRE = re.compile(r'([\w\s]+) \(.*')

    PRESENT = 'Present'
    PRETERITE = 'Preterite'

    Tenses = {
        PRESENT : Tense(name=PRESENT),
        PRETERITE : Tense(name=PRETERITE),
    }
    db.session.add(Tenses[PRESENT])
    db.session.add(Tenses[PRETERITE])
    db.session.commit()

    PresentTense = Tenses[PRESENT]
    PreteriteTense = Tenses[PRETERITE]

    FIRSTSING = '1s'
    SECONDSING = '2s'
    THIRDSING = '3s'
    FIRSTPLUR = '1p'
    THIRDPLUR = '3p'

    PersonPronouns = {
        FIRSTSING : [ 'yo' ],
        SECONDSING : [ 'tú' ],
        THIRDSING : [ 'él', 'ella', 'usted' ],
        FIRSTPLUR : [ 'nosotros', 'nosotras' ],
        THIRDPLUR : [ 'ellos', 'ellas', 'ustedes' ],
    }

    Persons = {}
    PersonOrder = [ FIRSTSING, SECONDSING, THIRDSING, FIRSTPLUR, THIRDPLUR ]

    plural = False
    for p in PersonOrder:
        if p.endswith('p'):
            plural = True
        Persons[p] =  Person(name=p, plural=plural)
        db.session.add(Persons[p])
        for pn in PersonPronouns[p]:
            db.session.add(Pronoun(pronoun=pn, person=Persons[p]))
    db.session.commit()

    Person1S = Persons[FIRSTSING]
    Person2S = Persons[SECONDSING]
    Person3S = Persons[THIRDSING]
    Person1P = Persons[FIRSTPLUR]
    Person3P = Persons[THIRDPLUR]

    db.session.add(Ending(ending='ar', newending='o', person_id=Person1S.id, 
                              tense_id=PresentTense.id))
    db.session.add(Ending(ending='er', newending='o', person_id=Person1S.id, 
                              tense_id=PresentTense.id))
    db.session.add(Ending(ending='ir', newending='o', person_id=Person1S.id, 
                              tense_id=PresentTense.id))

    db.session.add(Ending(ending='ar', newending='as',
                              person_id=Person2S.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='er', newending='es',
                              person_id=Person2S.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='ir', newending='es',
                              person_id=Person2S.id, tense_id=PresentTense.id))

    db.session.add(Ending(ending='ar', newending='a', person_id=Person3S.id, 
                              tense_id=PresentTense.id))
    db.session.add(Ending(ending='er', newending='e', person_id=Person3S.id, 
                              tense_id=PresentTense.id))
    db.session.add(Ending(ending='ir', newending='e', person_id=Person3S.id, 
                              tense_id=PresentTense.id))

    db.session.add(Ending(ending='ar', newending='amos',
                              person_id=Person1P.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='er', newending='emos',
                              person_id=Person1P.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='ir', newending='imos',
                              person_id=Person1P.id, tense_id=PresentTense.id))

    db.session.add(Ending(ending='ar', newending='an',
                              person_id=Person3P.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='er', newending='en',
                              person_id=Person3P.id, tense_id=PresentTense.id))
    db.session.add(Ending(ending='ir', newending='en',
                              person_id=Person3P.id, tense_id=PresentTense.id))

    db.session.commit()

    # Preterite

    db.session.add(Ending(ending='ar', newending='é', person_id=Person1S.id, 
                          tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='er', newending='í', person_id=Person1S.id, 
                          tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='ir', newending='í', person_id=Person1S.id, 
                          tense_id=PreteriteTense.id))

    db.session.add(Ending(ending='ar', newending='aste',
                          person_id=Person2S.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='er', newending='iste',
                          person_id=Person2S.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='ir', newending='iste',
                          person_id=Person2S.id, tense_id=PreteriteTense.id))

    db.session.add(Ending(ending='ar', newending='ó', person_id=Person3S.id, 
                          tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='er', newending='ió', person_id=Person3S.id, 
                          tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='ir', newending='ió', person_id=Person3S.id, 
                          tense_id=PreteriteTense.id))

    db.session.add(Ending(ending='ar', newending='amos',
                          person_id=Person1P.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='er', newending='imos',
                          person_id=Person1P.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='ir', newending='imos',
                          person_id=Person1P.id, tense_id=PreteriteTense.id))

    db.session.add(Ending(ending='ar', newending='aron',
                          person_id=Person3P.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='er', newending='ieron',
                          person_id=Person3P.id, tense_id=PreteriteTense.id))
    db.session.add(Ending(ending='ir', newending='ieron',
                          person_id=Person3P.id, tense_id=PreteriteTense.id))

    db.session.commit()

    verbs = [
        ( 'abrir', 'to open',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'aprender', 'to learn',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'arreglar', [ 'to fix', 'to arrange' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'ayudar', 'to help',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'bailar', 'to dance',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'bajar', [ 'to lower', 'to get out (of a vehicle)' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'buscar', 'to look for',
            {
                PRESENT : None,
                PRETERITE : [ 'busqué', None, None, None, None ],
            }
        ),
        ( 'cambiar', [ 'to change', 'to exchange' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'caminar', 'to walk',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'cantar', 'to sing',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'cocinar', 'to cook',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'comer', 'to eat',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'comprar', 'to buy',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'contestar', 'to answer',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'correr', 'to run',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'creer', 'to believe',
            {
                PRESENT : None,
                PRETERITE : [ None, 'creíste', 'creyó', 'creímos', 'creyeron' ],
            }
        ),
        ( 'decidir', 'to decide',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'dejar', 'to leave behind',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'descansar', 'to rest',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'escribir', 'to write',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'escuchar', 'to listen to',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'esperar', [ 'to wait (for)', 'to hope' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'estudiar', 'to study',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'firmar', 'to sign',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'ganar', [ 'to earn', 'to win' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'gastar', [ 'to spend', 'to waste' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'gustar', 'to like',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'hablar', 'to speak',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'invitar', 'to invite',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'lavar', 'to wash',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'leer', 'to read',
            {
                PRESENT : None,
                PRETERITE : [ None, 'leíste', 'leyó', 'leímos', 'leyeron' ],
            }
        ),
        ( 'llegar', 'to arrive',
            {
                PRESENT : None,
                PRETERITE : [ 'llegué', None, None, None, None ],
            }
        ),
        ( 'llenar', 'to fill',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'llevar', [ 'to carry', 'to wear' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'limpiar', 'to clean',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'mandar', [ 'to mail', 'to send' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'manejar', [ 'to drive', 'to manage' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'necesitar', 'to need',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'ordenar', 'to order',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'olvidar', 'to forget',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'pagar', 'to pay',
            {
                PRESENT : None,
                PRETERITE : [ 'pagué', None, None, None, None ],
            }
        ),
        ( 'pasar', [ 'to pass (by)', 'to happen', 'to spend (time)' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'platicar', 'to chat',
            {
                PRESENT : None,
                PRETERITE : [ 'platiqué', None, None, None, None ],
            }
        ),
        ( 'preguntar', 'to ask',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'preparar', 'to prepare',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'presentar', 'to introduce',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'quitar', 'to remove (from a surface)',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'recibir', 'to receive',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'recomendar', 'to recommend',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'regresar', 'to return',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'sacar', [ 'to take out', 'to take (a photo)' ],
            {
                PRESENT : None,
                PRETERITE : [ 'saqué', None, None, None, None ],
            }
        ),
        ( 'subir', [ 'to go up', 'to get into (a vehicle)' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'terminar', [ 'to finish', 'to terminate' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'tocar', [ 'to touch', 'to play (musical instrument)' ],
            {
                PRESENT : None,
                PRETERITE : [ 'toqué', None, None, None, None ],
            }
        ),
        ( 'trabajar', 'to work',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'tratar', 'to try',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'usar', [ 'to use', 'to wear' ],
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'vender', 'to sell',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'viajar', 'to travel',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'visitar', 'to visit',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),
        ( 'vivir', 'to live',
            {
                PRESENT : None,
                PRETERITE : None,
            }
        ),

    # irr_verbs in present start here

        ( 'dar', 'to give',
            {
                PRESENT : [ 'doy', 'das', 'da', 'damos', 'dan' ],
                PRETERITE : [ 'di', 'diste', 'dio', 'dimos', 'dieron' ],
            }
        ),
        ( 'estar', 'to be (feelings, location)',
            {
                PRESENT : [ 'estoy', 'estás', 'está', 'estamos', 'están' ],
                PRETERITE : [ 'estuve', 'estuviste', 'estuvo', 'estuvimos', 
                              'estuvieron' ],
            }
        ),
        ( 'ir', 'to go',
            {
                PRESENT : [ 'voy', 'vas', 'va', 'vamos', 'van' ],
                PRETERITE : [ 'fui', 'fuiste', 'fue', 'fuimos', 'fueron' ],
            }
        ),
        ( 'ser', 'to be (permanent)',
            {
                PRESENT : [ 'soy', 'eres', 'es', 'somos', 'son' ],
                PRETERITE : [ 'fui', 'fuiste', 'fue', 'fuimos', 'fueron' ],
            }
        ),
        ( 'tener', 'to have',
            {
                PRESENT : [ 'tengo', 'tienes', 'tiene', None, 'tienen' ],
                PRETERITE : [ 'tuve', 'tuviste', 'tuvo', 'tuvimos', 'tuvieron' ],
            }
        ),
        ( 'venir', 'to come',
            {
                PRESENT : [ 'vengo', 'vienes', 'viene', None, 'vienen' ],
                PRETERITE : [ 'vine', 'viniste', 'vino', 'vinimos', 'vinieron' ],
            }
        ),

    # irregular first person only in the present
    # good reference: https://studyspanish.com/verbs
    # also: https://www.spanishdict.com/conjugate/

        ( 'hacer', [ 'to do', 'to make' ],
            {
                PRESENT : [ 'hago', None, None, None, None ],
                PRETERITE : [ 'hice', 'hiciste', 'hizo', 'hicimos', 'hicieron' ],
            }
        ),
        ( 'poner', [ 'to put', 'to place' ],
            {
                PRESENT : [ 'pongo', None, None, None, None ],
                PRETERITE : [ 'puse', 'pusiste', 'puso', 'pusimos', 'pusieron' ],
            }
        ),
        ( 'saber', 'to know (something)',
            {
                PRESENT : [ 'sé', None, None, None, None ],
                PRETERITE : [ 'supe', 'supiste', 'supo', 'supimos', 'supieron' ],
            }
        ),
        ( 'salir', 'to leave',
            {
                PRESENT : [ 'salgo', None, None, None, None ],
                PRETERITE : None,
            }
        ),
        ( 'traer', 'to bring',
            {
                PRESENT : [ 'traigo', None, None, None, None ],
                PRETERITE : [ 'traje', 'trajiste', 'trajo', 'trajimos', 
                              'trajeron' ],
            }
        ),
        ( 'ver', 'to see',
            {
                PRESENT : [ 'veo', None, None, None, None ],
                PRETERITE : [ 'vi', None, 'vio', None, None ],
            }
        ),

    # stem-changing e:i

        ( 'pedir', 'to ask for',
            {
                PRESENT : [ 'pido', 'pides', 'pide', None, 'piden' ],
                PRETERITE : [ None, None, 'pidió', None, 'pidieron' ],
            }
        ),

    # stem-changing e:i with extra weirdness

        ( 'decir', [ 'to say', 'to tell' ],
            {
                PRESENT : [ 'digo', 'dices', 'dice', None, 'dicen' ],
                PRETERITE : [ 'dije', 'dijiste', 'dijo', 'dijimos', 'dijeron' ],
            }
        ),

    # stem-changing e:ie

        ( 'cerrar', 'to close',
            {
                PRESENT : [ 'cierro', 'cierras', 'cierra', None, 'cierran' ],
                PRETERITE : None,
            }
        ),
        ( 'empezar', 'to start',
            {
                PRESENT : [ 'empiezo', 'empiezas', 'empieza', None, 'empiezan' ],
                PRETERITE : [ 'empecé', None, None, None, None ],
            }
        ),
        ( 'entender', 'to understand',
            {
                PRESENT : [ 'entiendo', 'entiendes', 'entiende', None, 
                            'entienden' ],
                PRETERITE : None,
            }
        ),
        ( 'pensar', 'to think (about)',
            {
                PRESENT : [ 'pienso', 'piensas', 'piensa', None, 'piensan' ],
                PRETERITE : None,
            }
        ),
        ( 'perder', 'to lose',
            {
                PRESENT : [ 'pierdo', 'pierdes', 'pierde', None, 'pierden' ],
                PRETERITE : None,
            }
        ),
        ( 'querer', 'to want',
            {
                PRESENT : [ 'quiero', 'quieres', 'quiere', None, 'quieren' ],
                PRETERITE : [ 'quise', 'quisiste', 'quiso', 'quisimos', 
                              'quisieron' ],
            }
        ),

    # stem-changing o:ue

        ( 'dormir', 'to sleep',
            {
                PRESENT : [ 'duermo', 'duermes', 'duerme', None, 'duermen' ],
                PRETERITE : [ None, None, 'durmió', None, 'durmieron' ],
            }
        ),
        ( 'encontrar', [ 'to find', 'to encounter' ],
            {
                PRESENT : [ 'encuentro', 'encuentras', 'encuentra', None,
                                                            'encuentran' ],
                PRETERITE : None,
            }
        ),
        ( 'mover', 'to move (something)',
            {
                PRESENT : [ 'muevo', 'mueves', 'mueve', None, 'mueven' ],
                PRETERITE : None,
            }
        ),
        ( 'poder', 'to be able to',
            {
                PRESENT : [ 'puedo', 'puedes', 'puede', None, 'pueden' ],
                PRETERITE : [ 'pude', 'pudiste', 'pudo', 'pudimos', 'pudieron' ],
            }
        ),
        ( 'probar', [ 'to test', 'to taste' ],
            {
                PRESENT : [ 'pruebo', 'pruebas', 'prueba', None, 'prueban' ],
                PRETERITE : None,
            }
        ),
        ( 'recordar', 'to remember',
            {
                PRESENT : [ 'recuerdo', 'recuerdan', 'recuerda', None, 
                            'recuerdan' ],
                PRETERITE : None,
            }
        ),

    # stem-changing u:ue

        ( 'jugar', [ 'to play (sport or game)', 'to bet' ],
            {
                PRESENT : [ 'juego', 'juegas', 'juega', None, 'juegan' ],
                PRETERITE : [ 'jugué', None, None, None, None ],
            }
        ),
    # orthographic changes

        ( 'conocer', [ 'to know', 'to meet (for the first time)' ],
            {
                PRESENT : [ 'conozco', None, None, None, None ],
                PRETERITE : None,
            }
        ),
        ( 'conseguir', [ 'to get', 'to obtain' ],
            {
                PRESENT : [ 'consigo', 'consigues', 'consigue', None, 'consiguen' ],
                PRETERITE : [ None, None, 'consiguió', None, 'consiguieron' ],
            }
        ),
        ( 'oir', 'to hear',
            {
                PRESENT : [ 'oigo', 'oyes', 'oye', 'oimos', 'oyen' ],
                PRETERITE : [ None, 'oíste', 'oyó', 'oímos', 'oyeron' ],
            }
        ),
        ( 'seguir',  'to follow',
            {
                PRESENT : [ 'sigo', 'sigues', 'sigue', None, 'siguen' ],
                PRETERITE : [ None, None, 'siguió', None, 'siguieron' ],
            }
        ),

    ]

    for inf, trns, tenses in verbs:
        v = SpaVerb.query.filter(SpaVerb.infinitive == inf).first()
        if not v:
            stem = ending = None
            m = VerbRE.match(inf)
            if m:
                stem, ending = m.group(1), m.group(2)
            v = SpaVerb(infinitive=inf, stem=stem, ending=ending)
            db.session.add(v)
        if isinstance(trns, str):
            trns = [ trns ]
        for t in trns:
            e = EngVerb.query.filter(EngVerb.infinitive == t).first()
            if not e:
                e = EngVerb(infinitive=t)
                db.session.add(e)
            db.session.add(Translation(spa_verb=v, eng_verb=e))
        db.session.commit()

        for tense, words in tenses.items():
            if words is None:
                continue
            for idx, w in enumerate(words):
                if w:
                    db.session.add(Exception(conjugation=w, spa_verb=v,
                                     person_id=Persons[PersonOrder[idx]].id,
                                     tense_id=Tenses[tense].id))

        db.session.commit()

    return

if __name__ == '__main__':
    db_init()
