"""Change File table for hashfs.

Revision ID: adbd033b0dcd
Revises: 0563ce5ca262
Create Date: 2018-03-10 14:04:06.216924

"""
from alembic import op
import sqlalchemy as sa

from app import db, hashfs
from app.models.file import File

import os
import re

# revision identifiers, used by Alembic.
revision = 'adbd033b0dcd'
down_revision = '0563ce5ca262'


filename_regex = re.compile(r'(.+)\.([^\s.]+)')


def update_display_name_and_extension(f):
    m = filename_regex.match(f.display_name)
    if m is not None:
        f.display_name = m.group(1)
        f.extension = m.group(2).lower()
    else:
        f.extension = ""


def migrate_files():
    print("Migrating all existing files to HashFS")

    files = db.session.query(File).all()
    files_dir = 'app/static/files/'

    total = len(files)
    stepsize = 40

    files_to_delete = []

    for i, f in enumerate(files):
        if (i + 1) % stepsize == 0:
            print("{}/{}".format(i + 1, total))

        # Not an old file
        if len(f.hash) > 0:
            continue

        path = os.path.join(files_dir, f.display_name)
        if not os.path.isfile(path):
            print("File does not exist:", path)
            files_to_delete.append(f)
            continue

        with open(path, 'rb') as file_reader:
            address = hashfs.put(file_reader)

        f.hash = address.id

        update_display_name_and_extension(f)

    db.session.commit()

    if len(files_to_delete) > 0:
        print("Trying to delete non-existing files from the database...")
        total = len(files_to_delete)

        for i, f in enumerate(files_to_delete):
            print("{}/{}".format(i + 1, total))
            try:
                db.session.delete(f)
                db.session.commit()
            except:
                db.session.rollback()
                print("Could not delete file {} '{}'".format(
                    f.id, f.display_name))
                print("Setting its content to empty")

                update_display_name_and_extension(f)
                f.hash = '0' * 64

                db.session.commit()


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('file', 'name', new_column_name='display_name', existing_type=sa.String(length=200))
    op.add_column('file', sa.Column('category', sa.Enum('UPLOADS', 'EXAMINATION', 'ACTIVITY_PICTURES', 'ALV_DOCUMENT', 'COMPANY_LOGO', 'USER_AVATAR', name='filecategory'), nullable=False))
    op.add_column('file', sa.Column('extension', sa.String(length=20), nullable=False))
    op.add_column('file', sa.Column('hash', sa.String(length=200), nullable=False))
    op.create_unique_constraint(op.f('uq_file_display_name'), 'file', ['display_name', 'extension'])
    op.drop_index('uq_file_name', table_name='file')
    op.drop_constraint('file_ibfk_1', 'file', type_='foreignkey')
    op.drop_column('file', 'page_id')
    # ### end Alembic commands ###

    try:
        migrate_files()
    except Exception as e:
        print("====== Migrating files failed! ======")
        print("Please try to fix the error and run migrate_files() manually.")
        raise e


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    raise Exception("Undoing this migration is impossible")

    # op.alter_column('file', 'display_name', new_column_name='name', existing_type=sa.String(length=200))
    # op.add_column('file', sa.Column('page_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
    # op.create_foreign_key('file_ibfk_1', 'file', 'page', ['page_id'], ['id'])
    # op.create_index('uq_file_name', 'file', ['name'], unique=True)
    # op.drop_constraint(op.f('uq_file_display_name'), 'file', type_='unique')
    # op.drop_column('file', 'hash')
    # op.drop_column('file', 'extension')
    # op.drop_column('file', 'category')
    # ### end Alembic commands ###
