"""remove base models

Revision: 0071
Revision ID: 4ed4e16e500e
Revises: 8a9754acb4a
Create Date: 2016-08-31 18:04:31.831146

"""

# revision identifiers, used by Alembic.
revision = '4ed4e16e500e'
down_revision = '8a9754acb4a'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa
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),
    sa.Column('attribute_group_id', sa.Integer)
)

projects_table = sa.Table(
    'projects',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('base_card_model_id', sa.Integer),
    sa.Column('attribute_group_id', sa.Integer),
    sa.Column('use_org_attributes', sa.Boolean)
)

cards_table = sa.Table(
    'cards',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('project_id', sa.Integer)
)

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('extends_id', sa.Integer),
    sa.Column('dynamic_extends', sa.String),
    sa.Column('attribute_group_id', sa.Integer),
    sa.Column('created_at', sa.DateTime)
)

attribute_groups_table = sa.Table(
    'attribute_groups',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('created_at', sa.DateTime)
)

attributes_table = sa.Table(
    'attributes',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('card_model_id', sa.Integer),
    sa.Column('card_id', sa.Integer),
    sa.Column('name', sa.String),
    sa.Column('description', sa.Text),
    sa.Column('type_name', sa.String),
    sa.Column('container', sa.String),
    sa.Column('position', sa.Integer),
    sa.Column('options', sa.PickleType),
    sa.Column('default_value', sa.PickleType),
    sa.Column('is_from_builtin', sa.Boolean),
    sa.Column('show_on_tile', sa.Boolean),
    sa.Column('group_id', sa.Integer)
)

card_attributes_table = sa.Table(
    'card_attributes',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('attribute_id', sa.Integer),
    sa.Column('card_id', sa.Integer)
)


def upgrade():
    op.add_column('organizations', sa.Column('attribute_group_id', sa.Integer(), nullable=True))
    op.create_index(op.f('ix_organizations_attribute_group_id'), 'organizations', ['attribute_group_id'], unique=False)
    op.create_foreign_key('organizations_attribute_groups', 'organizations', 'attribute_groups', ['attribute_group_id'], ['id'], ondelete='SET NULL')

    op.add_column('projects', sa.Column('attribute_group_id', sa.Integer(), nullable=True))
    op.add_column('projects', sa.Column('use_org_attributes', sa.Boolean(), nullable=True, server_default="True"))
    op.create_index(op.f('ix_projects_attribute_group_id'), 'projects', ['attribute_group_id'], unique=False)
    op.create_index(op.f('ix_projects_use_org_attributes'), 'projects', ['use_org_attributes'], unique=False)
    op.create_foreign_key('projects_attribute_groups', 'projects', 'attribute_groups', ['attribute_group_id'], ['id'], ondelete='SET NULL')

    conn = op.get_bind()
    for org in conn.execute(orgs_table.select()):
        model_to_delete = []
        for project in conn.execute(projects_table.select().where(projects_table.c.owner_id == org.id)):
            base_card_model_id = project.base_card_model_id
            base_card_model = conn.execute(card_models_table.select().where(sa.and_(card_models_table.c.id == base_card_model_id, card_models_table.c.is_base == 'project'))).first()
            if not base_card_model:
                continue
            group_id = base_card_model.attribute_group_id
            if base_card_model_id not in model_to_delete:
                model_to_delete.append(base_card_model_id)
            else:
                r = conn.execute(attribute_groups_table.insert().values(
                    owner_id=org.id,
                    created_at=base_card_model.created_at
                ))
                group_id = r.inserted_primary_key[0]
                card_ids = None
                for attr in conn.execute(attributes_table.select().where(attributes_table.c.group_id == base_card_model.attribute_group_id)):
                    r = conn.execute(attributes_table.insert().values(
                        card_model_id=attr.card_model_id,
                        card_id=attr.card_id,
                        name=attr.name,
                        description=attr.description,
                        type_name=attr.type_name,
                        container=attr.container,
                        position=attr.position,
                        options=attr.options,
                        default_value=attr.default_value,
                        is_from_builtin=attr.is_from_builtin,
                        show_on_tile=attr.show_on_tile,
                        group_id=group_id
                    ))
                    attribute_id = r.inserted_primary_key[0]
                    if card_ids is None:
                        card_ids = []
                        for card in conn.execute(cards_table.select().where(cards_table.c.project_id==project.id)):
                            card_ids.append(card.id)
                    conn.execute(card_attributes_table.update().where(sa.and_(card_attributes_table.c.attribute_id == attr.id, card_attributes_table.c.card_id.in_(card_ids))).values(
                        attribute_id = attribute_id
                    ))

            conn.execute(projects_table.update().where(projects_table.c.id == project.id).values(
                attribute_group_id = group_id,
                use_org_attributes = base_card_model.dynamic_extends == 'org' or base_card_model.extends_id == org.default_card_model_id
            ))

        if model_to_delete:
            stmt = card_models_table.delete().where(card_models_table.c.id == sa.bindparam('id'))
            conn.execute(stmt, [{'id': model_id} for model_id in model_to_delete])

        org_base_model_id = org.default_card_model_id
        org_base_model = conn.execute(card_models_table.select().where(sa.and_(card_models_table.c.id == org_base_model_id, card_models_table.c.is_base == 'org'))).first()
        if not org_base_model:
            continue
        conn.execute(orgs_table.update().where(orgs_table.c.id == org.id).values(
            attribute_group_id = org_base_model.attribute_group_id
        ))
        op.execute("DELETE FROM card_models WHERE id = %s" % org_base_model_id)

    op.drop_constraint('organizations_default_card_model_id_fkey', 'organizations', type_='foreignkey')

    op.drop_constraint('projects_base_card_model_id_fkey', 'projects', type_='foreignkey')
    op.drop_column('projects', 'base_card_model_id')


def downgrade():
    op.add_column('projects', sa.Column('base_card_model_id', sa.INTEGER(), autoincrement=False, nullable=True))
    op.create_foreign_key('projects_base_card_model_id_fkey', 'projects', 'card_models', ['base_card_model_id'], ['id'])

    op.create_foreign_key('organizations_default_card_model_id_fkey', 'organizations', 'card_models', ['default_card_model_id'], ['id'])

    op.drop_constraint('projects_attribute_groups', 'projects', type_='foreignkey')
    op.drop_index(op.f('ix_projects_use_org_attributes'), table_name='projects')
    op.drop_index(op.f('ix_projects_attribute_group_id'), table_name='projects')
    op.drop_column('projects', 'use_org_attributes')
    op.drop_column('projects', 'attribute_group_id')

    op.drop_constraint('organizations_attribute_groups', 'organizations', type_='foreignkey')
    op.drop_index(op.f('ix_organizations_attribute_group_id'), table_name='organizations')
    op.drop_column('organizations', 'attribute_group_id')
