"""models without builtin, listable

Revision: 0037
Revision ID: 11af45c6c79e
Revises: 52ccef8b0e0
Create Date: 2015-11-26 16:28:18.436640

"""

# revision identifiers, used by Alembic.
revision = '11af45c6c79e'
down_revision = '52ccef8b0e0'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa
import datetime
import uuid
from sqlalchemy.dialects import postgresql

orgs_table = sa.Table(
    'organizations',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('default_card_model_id', sa.Integer),
    sa.Column('is_user_org', sa.Boolean)
)

card_models_table = sa.Table(
    'card_models',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('is_base', sa.String),
    sa.Column('name', sa.String),
    sa.Column('extends_id', sa.Integer),
    sa.Column('created_in_id', sa.Integer),
    sa.Column('created_at', sa.DateTime),
    sa.Column('auto_enabled_on_new_projects', sa.Boolean),
    sa.Column('has_builtin_attributes', sa.Boolean),
    sa.Column('dynamic_extends', sa.String),
    sa.Column('is_project_specific', sa.String),
    sa.Column('cache_id', sa.String)
)


card_model_attributes_table = sa.Table(
    'card_model_attributes',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('card_model_id', sa.Integer),
    sa.Column('position', sa.Integer),
    sa.Column('name', sa.String),
    sa.Column('title', sa.String),
    sa.Column('type_name', sa.String),
    sa.Column('container', sa.String),
    sa.Column('is_from_builtin', sa.Boolean)
)

cards_table = sa.Table(
    'cards',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('model_id', sa.Integer),
    sa.Column('base_card_model_id', sa.Integer),
    sa.Column('parent_id', sa.Integer),
    sa.Column('parents_ids', postgresql.ARRAY(sa.Integer)),
    sa.Column('default_child_card_model_id', sa.Integer),
    sa.Column('title', sa.String)
)

card_enabled_models_table = sa.Table(
    'card_enabled_models',
    sa.MetaData(),
    sa.Column('model_id', sa.Integer),
    sa.Column('card_id', sa.Integer)
)

def upgrade():
    op.add_column('card_model_attributes', sa.Column('is_from_builtin', sa.BOOLEAN(), server_default="False", nullable=False))
    op.drop_column('card_models', 'listable')
    op.add_column('card_models', sa.Column('is_project_specific', sa.BOOLEAN(), server_default="False", nullable=False))
    op.execute("UPDATE card_models SET is_project_specific=true WHERE created_in_id IS NOT NULL AND auto_enabled_on_new_projects = false")
    op.add_column('card_models', sa.Column('has_builtin_attributes', sa.BOOLEAN(), server_default="False", nullable=False))

    op.execute("DELETE FROM cards WHERE owner_id IS NULL")
    conn = op.get_bind()
    for org in conn.execute(orgs_table.select()):
        needOrgModel = True
        needDesc = needAssign = needDate = needLabel = needAttach = True

        org_model_id = org.default_card_model_id
        org_model = conn.execute(card_models_table.select().where(sa.and_(card_models_table.c.owner_id == org.id, card_models_table.c.is_base == 'org'))).first()
        if org_model:
            org_model_id = org_model.id
            needOrgModel = False
            for attr in conn.execute(card_model_attributes_table.select().where(card_model_attributes_table.c.card_model_id == org_model.id)):
                if attr.name == 'description' and attr.type_name == 'content':
                    needDesc = False
                if attr.name == 'assignees' and attr.type_name == 'members':
                    needAssign = False
                if attr.name == 'due_date' and attr.type_name == 'date':
                    needDate = False
                if attr.name == 'labels' and attr.type_name == 'labels':
                    needLabel = False
                if attr.name == 'attachments' and attr.type_name == 'files':
                    needAttach = False

        if needOrgModel:
            res = conn.execute(
                    card_models_table.insert().values(
                        owner_id=org.id,
                        name='User base model' if org.is_user_org else 'Organization base model',
                        auto_enabled_on_new_projects=True,
                        is_base='org',
                        created_at=datetime.datetime.utcnow(),
                        has_builtin_attributes=True,
                        cache_id=str(uuid.uuid4())))
            org_model_id = res.inserted_primary_key[0]

        op.execute("UPDATE organizations SET default_card_model_id = " + str(org_model_id) + " WHERE id = " + str(org.id))

        if needDesc:
            conn.execute(card_model_attributes_table.insert().values(card_model_id=org_model_id, position=0, name='description', title='Description', type_name='content', container='top', is_from_builtin=True))
        if needAssign:
            conn.execute(card_model_attributes_table.insert().values(card_model_id=org_model_id, position=1, name='assignees', title='Assignees', type_name='members', is_from_builtin=True))
        if needDate:
            conn.execute(card_model_attributes_table.insert().values(card_model_id=org_model_id, position=2, name='due_date', title='Due Date', type_name='date', is_from_builtin=True))
        if needLabel:
            conn.execute(card_model_attributes_table.insert().values(card_model_id=org_model_id, position=3, name='labels', title='Labels', type_name='labels', is_from_builtin=True))
        if needAttach:
            conn.execute(card_model_attributes_table.insert().values(card_model_id=org_model_id, position=4, name='attachments', title='Attachments', type_name='files', is_from_builtin=True))

        for card in conn.execute(cards_table.select().where(sa.and_(cards_table.c.owner_id == org.id, cards_table.c.parent_id == None))):
            model_id = card.model_id
            needProjectModel = 'create' if model_id == 1 else 'nothing'
            if needProjectModel == 'nothing':
                needProjectModel = True
                model = conn.execute(card_models_table.select().where(card_models_table.c.id == model_id)).first()
                if not model or model.is_base == 'org':
                    needProjectModel = 'create'
                elif not model.is_base:
                    needProjectModel = 'update'

            if needProjectModel == 'create':
                child = conn.execute(cards_table.select().where(cards_table.c.parent_id == card.id)).first()
                if child and child.model_id != 1:
                    child_model = conn.execute(card_models_table.select().where(card_models_table.c.id == child.model_id)).first()
                    if child_model.extends_id == 1:
                        model_id = child_model.id
                        conn.execute(card_models_table.update().where(card_models_table.c.id == model_id).values(
                            auto_enabled_on_new_projects=False,
                            is_base='project',
                            created_in_id=card.id,
                            extends_id=None,
                            dynamic_extends='org',
                            is_project_specific=True
                        ))
                        op.execute("UPDATE cards SET model_id = " + str(model_id) + ", base_card_model_id = " + str(model_id) + ", default_child_card_model_id = " + str(model_id) + " WHERE id = " + str(card.id))
                if model_id == card.model_id:
                    res = conn.execute(
                            card_models_table.insert().values(
                                owner_id=org.id,
                                name='%s base model' % card.title,
                                auto_enabled_on_new_projects=False,
                                is_base='project',
                                created_in_id=card.id,
                                created_at=datetime.datetime.utcnow(),
                                dynamic_extends='org',
                                is_project_specific=True,
                                cache_id=str(uuid.uuid4())))
                    model_id = res.inserted_primary_key[0]
                    op.execute("UPDATE cards SET model_id = " + str(model_id) + ", base_card_model_id = " + str(model_id) + ", default_child_card_model_id = " + str(model_id) + " WHERE id = " + str(card.id))
                    op.execute("UPDATE cards SET model_id = " + str(model_id) + " WHERE parents_ids[1] = " + str(card.id))
            if needProjectModel == 'update':
                dyn = "null" if model.extends_id is None else "'org'"
                op.execute("UPDATE card_models SET is_base='project', auto_enabled_on_new_projects=false, extends_id=null, dynamic_extends=" + dyn + ", is_project_specific=true, created_in_id=" + str(card.id) + " WHERE id = " + str(card.model_id))
            op.execute("UPDATE cards SET model_id = " + str(model_id) + " WHERE parents_ids[1] = " + str(card.id) + " AND model_id=1")

            res = conn.execute(card_enabled_models_table.select().where(sa.and_(card_enabled_models_table.c.model_id == org_model_id, card_enabled_models_table.c.card_id == card.id))).first()
            if res is None:
                op.execute("INSERT INTO card_enabled_models(model_id, card_id) VALUES (" + str(org_model_id) + ", " + str(card.id) +")")
            res = conn.execute(card_enabled_models_table.select().where(sa.and_(card_enabled_models_table.c.model_id == model_id, card_enabled_models_table.c.card_id == card.id))).first()
            if res is None:
                op.execute("INSERT INTO card_enabled_models(model_id, card_id) VALUES (" + str(model_id) + ", " + str(card.id) +")")

    op.execute("UPDATE cards AS c SET model_id=c2.model_id FROM cards AS c2 WHERE c.parents_ids[1]=c2.id AND (c.model_id=1 OR c.model_id IS NULL)")
    op.execute("UPDATE card_models SET extends_id = null WHERE is_base = 'org' AND extends_id = 1")
    op.execute("UPDATE card_models SET extends_id = null, dynamic_extends = 'org' WHERE extends_id = 1")
    op.execute("UPDATE card_models SET extends_id = null, dynamic_extends = 'org' FROM organizations WHERE extends_id = organizations.default_card_model_id")
    op.execute("UPDATE card_models AS cm SET extends_id = null, dynamic_extends = 'project' FROM card_models AS cm2 WHERE cm.extends_id = cm2.id AND cm2.is_base = 'project'")
    op.execute("UPDATE card_models SET children_default_model_id = null WHERE children_default_model_id = 1")
    op.execute("INSERT INTO card_enabled_models (model_id, card_id) SELECT model_id, parents_ids[1] FROM cards where parents_ids IS NOT NULL")
    op.execute("DELETE FROM card_enabled_models WHERE ctid NOT IN (SELECT min(ctid) FROM card_enabled_models GROUP BY model_id, card_id);")
    op.execute("DELETE FROM card_enabled_models WHERE model_id = 1")

    op.execute("UPDATE cards SET parents_ids = '{13925,27417}' where parent_id = 27417")
    op.execute("UPDATE cards SET parents_ids = '{13925,27417}' where parent_id = 22813")


def downgrade():
    op.drop_column('card_models', 'has_builtin_attributes')
    op.drop_column('card_model_attributes', 'is_from_builtin')
    op.add_column('card_models', sa.Column('listable', sa.BOOLEAN(), server_default="False", nullable=False))
    op.execute("UPDATE card_models SET listable = true WHERE is_base IS NULL AND is_project_specific = false AND auto_enabled_on_new_projects = true")
    op.drop_column('card_models', 'is_project_specific')
    op.execute("UPDATE card_models SET extends_id = 1 WHERE is_base = 'org'")
    op.execute("DELETE FROM card_model_attributes cma USING card_models cm WHERE cm.id = cma.card_model_id AND cm.extends_id = 1 AND cma.name in ('description', 'assignees', 'due date', 'labels', 'attachments')")
