"""labels_to_groups

Revision: 0041
Revision ID: 5409e2aad044
Revises: 23e5cefde476
Create Date: 2015-11-28 10:04:42.342027

"""

# revision identifiers, used by Alembic.
revision = '5409e2aad044'
down_revision = '23e5cefde476'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import select
from sqlalchemy.dialects import postgresql

card_attributes = sa.Table(
    'card_attributes',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('card_model_attribute_id', sa.Integer),
    sa.Column('card_id', sa.Integer),
    sa.Column('value', postgresql.JSONB)
)
card_model_attributes = sa.Table(
    'card_model_attributes',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('type_name', sa.String),
    sa.Column('name', sa.String),
    sa.Column('container', sa.String),
    sa.Column('is_from_builtin', sa.Boolean),
    sa.Column('card_model_id', sa.Integer),
    sa.Column('options', sa.PickleType)
)
card_models = sa.Table(
    'card_models',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer)
)
cards = sa.Table(
    'cards',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('parent_id', sa.Integer),
    sa.Column('parents_ids', postgresql.ARRAY(sa.Integer), default=list),
    sa.Column('children_attributes_ctx', sa.PickleType, default=dict)
)
card_enabled_group_types = sa.Table(
    'card_enabled_group_types',
    sa.MetaData(),
    sa.Column('group_type_id', sa.Integer),
    sa.Column('card_id', sa.Integer)
)
orgs = sa.Table(
    'organizations',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True)
)
card_group_types = sa.Table(
    'card_group_types',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('owner_id', sa.Integer),
    sa.Column('name', sa.String),
    sa.Column('singular_name', sa.String),
    sa.Column('plural_name', sa.String),
    sa.Column('scope', sa.String),
    sa.Column('one_group_per_card', sa.Boolean),
    sa.Column('display_on_card', sa.String),
    sa.Column('auto_random_color', sa.Boolean),
    sa.Column('builtin', sa.String),
    sa.Column('auto_enabled_on_new_projects', sa.Boolean),
    sa.Column('is_project_specific', sa.Boolean),
)
card_groups = sa.Table(
    'card_groups',
    sa.MetaData(),
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('parent_id', sa.Integer),
    sa.Column('group_type_id', sa.Integer),
    sa.Column('title', sa.String),
    sa.Column('color', sa.String),
    sa.Column('position', sa.Integer)
)
card_groups_cards = sa.Table(
    'card_groups_cards',
    sa.MetaData(),
    sa.Column('group_id', sa.Integer),
    sa.Column('card_id', sa.Integer),
    sa.Column('position', sa.Integer)
)

def upgrade():
    conn = op.get_bind()

    local_contexts = set()
    needed_groups = {}
    card_labels = {}

    q = select([card_attributes, cards.c.parent_id, cards.c.parents_ids, cards.c.owner_id])\
        .where(sa.and_(
            card_model_attributes.c.id == card_attributes.c.card_model_attribute_id,
            cards.c.id==card_attributes.c.card_id,
            card_model_attributes.c.type_name=='labels',
            card_model_attributes.c.is_from_builtin==True,
            cards.c.owner_id!=None
        ))
    for attr in conn.execute(q):
        if not attr.parent_id:
            root_id = attr.card_id
            ctx_id = attr.card_id
        else:
            root_id = attr.parents_ids[0]
            ctx_id = attr.parent_id
        if root_id not in needed_groups:
            needed_groups[root_id] = [{}, attr.owner_id]
        if ctx_id not in local_contexts:
            local_contexts.add(ctx_id)
            ctx = conn.execute(select([cards.c.children_attributes_ctx])
                .where(cards.c.id==ctx_id)).scalar()
            for title, color in ctx.get('labels:labels', {}).items():
                needed_groups[root_id][0].setdefault(title, color)
        if attr.value:
            for title in attr.value:
                needed_groups[root_id][0].setdefault(title, None)
            card_labels[attr.card_id] = (attr.value, root_id)

    gtypes = {}
    for org in conn.execute(select([orgs.c.id])):
        r = conn.execute(card_group_types.insert().values(
            owner_id=org.id,
            name='Labels',
            singular_name='label',
            plural_name='labels',
            scope='project',
            one_group_per_card=False,
            display_on_card='border',
            auto_random_color=True,
            builtin='LABELS',
            auto_enabled_on_new_projects=True,
            is_project_specific=False
        ))
        gtypes[org.id] = r.inserted_primary_key[0]
        conn.execute(card_enabled_group_types.insert().from_select(['group_type_id', 'card_id'],
            select([sa.text(str(gtypes[org.id])), cards.c.id]).where(
                sa.and_(cards.c.parent_id==None, cards.c.owner_id==org.id))))

        conn.execute(card_model_attributes.update().where(sa.and_(
            card_models.c.id==card_model_attributes.c.card_model_id,
            card_models.c.owner_id==org.id,
            card_model_attributes.c.type_name=='labels',
            card_model_attributes.c.name=='labels',
            card_model_attributes.c.container==None
        )).values(
            type_name='group_type',
            options={'group_type': gtypes[org.id]}
        ))

    groups = {}
    for id, spec in needed_groups.items():
        groups[id] = {}
        type_id = gtypes[spec[1]]
        for title, color in spec[0].items():
            r = conn.execute(card_groups.insert().values(
                parent_id=id,
                group_type_id=type_id,
                title=title,
                color=color,
                position=len(groups[id].items())))
            groups[id][title] = r.inserted_primary_key[0]

    positions = {}
    values = []
    for id, spec in card_labels.items():
        for title in spec[0]:
            gid = groups[spec[1]][title]
            values.append({'card_id': id, 'group_id': gid, 'position': positions.get(gid, 0)})
            positions[gid] = positions.get(gid, 0) + 1
    op.bulk_insert(card_groups_cards, values)

    op.execute("""DELETE FROM card_attributes USING card_model_attributes
            WHERE card_model_attributes.id = card_attributes.card_model_attribute_id AND
            card_model_attributes.is_from_builtin AND card_attributes.type_name = 'labels'""")


def downgrade():
    pass
