#!/usr/bin/python
# -*- coding: utf-8 -*-
"""ORM for index server."""
import time
from datetime import datetime
import peewee
from playhouse.db_url import connect
from pacifica.ingest.config import get_config

DATABASE_CONNECT_ATTEMPTS = 20
DATABASE_WAIT = 5
DB = connect(get_config().get('database', 'peewee_url'))


def database_setup(attempts=0):
    """Attempt to connect to the database."""
    try:
        IngestState.database_connect()
        if not IngestState.table_exists():
            IngestState.create_table()
        IngestState.database_close()
    except peewee.OperationalError:
        if attempts < DATABASE_CONNECT_ATTEMPTS:
            time.sleep(DATABASE_WAIT)
            attempts += 1
            database_setup(attempts)
        else:
            raise peewee.OperationalError


# pylint: disable=too-few-public-methods
class BaseModel(peewee.Model):
    """Auto-generated by pwiz."""

    class Meta(object):
        """Map to the database connected above."""

        database = DB


class IngestState(BaseModel):
    """Map a python record to a mysql table."""

    job_id = peewee.BigIntegerField(primary_key=True, db_column='id')
    state = peewee.CharField()
    task = peewee.CharField()
    task_percent = peewee.DecimalField()
    exception = peewee.TextField(default='')
    created = peewee.DateTimeField(default=datetime.utcnow)
    updated = peewee.DateTimeField(default=datetime.utcnow)

    @classmethod
    def database_connect(cls):
        """
        Make sure database is connected.

        Trying to connect a second
        time *does* cause problems.
        """
        # pylint: disable=no-member
        if not cls._meta.database.is_closed():
            cls._meta.database.close()
        cls._meta.database.connect()
        # pylint: enable=no-member

    @classmethod
    def database_close(cls):
        """
        Close the database connection.

        Closing already closed database
        is not a problem, so continue on.
        """
        # pylint: disable=no-member
        if not cls._meta.database.is_closed():
            cls._meta.database.close()
        # pylint: enable=no-member

    class Meta(object):
        """Map to uniqueindex table."""

        db_table = 'ingeststate'
# pylint: enable=too-few-public-methods


def update_state(job_id, state, task, task_percent, exception=''):
    """Update the state of an ingest job."""
    if job_id and int(job_id) >= 0:
        IngestState.database_connect()
        record = IngestState.get_or_create(job_id=job_id,
                                           defaults={'task': '', 'task_percent': 0, 'state': ''})[0]

        record.state = state
        record.task = task
        record.task_percent = task_percent
        record.exception = exception
        record.updated = datetime.utcnow()
        record.save()
        IngestState.database_close()


def read_state(job_id):
    """Return the state of an ingest job as a json object."""
    IngestState.database_connect()
    if job_id and job_id >= 0:
        record = IngestState.get(job_id=job_id)
    else:
        record = IngestState()
        record.state = 'DATA_ACCESS_ERROR'
        record.task = 'read_state'
        record.task_percent = 0
    IngestState.database_close()
    return record
