# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-05-09 15:35
from __future__ import unicode_literals

import logging
import os

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models

import pootle.core.user
from pootle.core.batch import Batch
from pootle.core.url_helpers import split_pootle_path
from pootle.core.user import get_system_user_id
from pootle_statistics.models import SubmissionTypes

logger = logging.getLogger(__name__)

UNIT_CREATE_TYPE = 10

UNIT_SOURCE_SQL = (
    "INSERT INTO `pootle_store_unit_source` "
    "  (`unit_id`, `created_with`, `created_by_id`, `source_hash`, `source_length`, `source_wordcount`) "
    "(SELECT `id` as `unit_id`, "
    "  %s as `created_with`, "
    "  %s as `created_by_id`, "
    "  `source_hash` as `source_hash`,"
    "  `source_length` as `source_length`,"
    "  `source_wordcount` as `source_wordcount`"
    "  from `pootle_store_unit`)")

UNIT_CHANGE_SQL = (
    "INSERT INTO `pootle_store_unit_change` "
    "  (`unit_id`, `changed_with`, `commented_on`, `commented_by_id`, `reviewed_on`, `reviewed_by_id`, `submitted_on`, `submitted_by_id`) "
    " (SELECT `id` as `unit_id`, "
    "  %s as `changed_with`, "
    "  `commented_on` as `commented_on`,"
    "  `commented_by_id` as `commented_by_id`,"
    "  `reviewed_on` as `reviewed_on`,"
    "  `reviewed_by_id` as `reviewed_by_id`,"
    "  `submitted_on` as `submitted_on`,"
    "  `submitted_by_id` as `submitted_by_id`"
    "  from `pootle_store_unit` "
    "  WHERE "
    "   ((`pootle_store_unit`.`translator_comment` is not NULL "
    "     AND (`commented_on` is not NULL "
    "          OR `commented_by_id` is not NULL)) "
    "    OR (`reviewed_on` is not NULL "
    "        OR `reviewed_by_id` is not NULL) "
    "    OR (`submitted_on` is not NULL "
    "        OR `submitted_by_id` is not NULL)))")

UNIT_DELETE_COLS_SQL = (
    "ALTER TABLE `pootle_store_unit` %s")

REMOVED_UNIT_COLS = [
    "source_hash",
    "source_length",
    "source_wordcount",
    "commented_on",
    "commented_by_id",
    "reviewed_by_id",
    "reviewed_on",
    "submitted_by_id",
    "submitted_on"]


class OLDSuggestionStates(object):
    PENDING = 'pending'
    ACCEPTED = 'accepted'
    REJECTED = 'rejected'


def _missing_changes(apps):
    units = apps.get_model("pootle_store.Unit").objects.all()
    changeless = units.filter(change__isnull=True)

    missing_comments = changeless.filter(translator_comment__gt="")
    missing_comments = (
        missing_comments.filter(commented_by_id__isnull=False)
        | missing_comments.filter(commented_on__isnull=False))
    missing_reviews = (
        changeless.filter(reviewed_by_id__isnull=False)
        | changeless.filter(reviewed_on__isnull=False))
    missing_submits = (
        changeless.filter(submitted_by_id__isnull=False)
        | changeless.filter(submitted_on__isnull=False))
    return (missing_comments | missing_reviews | missing_submits)


def create_sources_with_orm(apps, creators):
    sysuser = get_system_user_id()
    UnitSource = apps.get_model("pootle_store.UnitSource")
    units = apps.get_model("pootle_store.Unit").objects.all()
    _units = list(
        units.values_list(
            "id",
            "source_hash",
            "source_length",
            "source_wordcount").iterator())

    def _unit_source_create(pk, source_hash, source_length, source_wordcount):
        return dict(
            unit_id=pk,
            source_hash=source_hash,
            source_wordcount=source_wordcount,
            source_length=source_length,
            created_with=SubmissionTypes.WEB,
            created_by_id=creators.get(pk, sysuser))
    Batch(UnitSource.objects, batch_size=500).create(
        _units,
        _unit_source_create,
        reduces=False)


def update_sources_with_orm(apps, creators):
    UnitSource = apps.get_model("pootle_store.UnitSource")

    def _set_created_by(unit_source):
        unit_source.created_by_id = creators.get(unit_source.unit_id)
        return unit_source
    Batch(UnitSource.objects, batch_size=500).update(
        list(UnitSource.objects.filter(unit_id__in=creators.keys())),
        update_method=_set_created_by,
        update_fields=["created_by"],
        reduces=False)


def create_changes_with_orm(apps):
    UnitChange = apps.get_model("pootle_store.UnitChange")
    missing = list(
        _missing_changes(apps).iterator())

    def _unit_change_create(unit):
        return dict(
            unit_id=unit.pk,
            changed_with=SubmissionTypes.WEB,
            commented_by_id=unit.commented_by_id,
            commented_on=unit.commented_on,
            reviewed_by_id=unit.reviewed_by_id,
            reviewed_on=unit.reviewed_on,
            submitted_by_id=unit.submitted_by_id,
            submitted_on=unit.submitted_on)
    Batch(UnitChange.objects, batch_size=500).create(
        missing,
        _unit_change_create,
        reduces=False)


def create_sources_with_sql(schema_editor):
    sysuser = get_system_user_id()
    cursor = schema_editor.connection.cursor()
    cursor.execute(UNIT_SOURCE_SQL % (SubmissionTypes.SYSTEM, sysuser))


def create_changes_with_sql(schema_editor):
    cursor = schema_editor.connection.cursor()
    cursor.execute(UNIT_CHANGE_SQL % SubmissionTypes.WEB)


def add_unit_sources(apps, schema_editor):
    subs = apps.get_model("pootle_statistics.Submission").objects.all()
    sysuser = get_system_user_id()
    creators = dict(
        subs.filter(type=UNIT_CREATE_TYPE)
            .exclude(submitter_id=sysuser)
            .values_list("unit_id", "submitter"))
    if schema_editor.connection.vendor == "mysql" and settings.POOTLE_SQL_MIGRATIONS:
        create_sources_with_sql(schema_editor)
        update_sources_with_orm(apps, creators)
    else:
        create_sources_with_orm(apps, creators)


def add_unit_changes(apps, schema_editor):
    if schema_editor.connection.vendor == "mysql" and settings.POOTLE_SQL_MIGRATIONS:
        create_changes_with_sql(schema_editor)
    else:
        create_changes_with_orm(apps)


def convert_unit_source_change(apps, schema_editor):
    add_unit_sources(apps, schema_editor)
    add_unit_changes(apps, schema_editor)


def add_default_suggestion_states(apps, schema_editor):
    states = apps.get_model("pootle_store.SuggestionState").objects
    for state in ["pending", "accepted", "rejected"]:
        states.create(name=state)


def set_suggestion_states(apps, schema_editor):
    # TODO: add sql path for this update
    suggestions = apps.get_model("pootle_store.Suggestion").objects.all()
    states = apps.get_model("pootle_store.SuggestionState").objects.all()
    pending = states.get(name="pending")
    accepted = states.get(name="accepted")
    rejected = states.get(name="rejected")
    suggestions.filter(tmp_state=OLDSuggestionStates.PENDING).update(state_id=pending.id)
    suggestions.filter(tmp_state=OLDSuggestionStates.ACCEPTED).update(state_id=accepted.id)
    suggestions.filter(tmp_state=OLDSuggestionStates.REJECTED).update(state_id=rejected.id)


def clean_abs_file_paths(apps, schema_editor):
    """Replace wrong absolute store file paths by proper relative paths

    built based on store.pootle_path values.
    """
    store_model = apps.get_model("pootle_store.Store")
    stores = store_model.objects.filter(
        translation_project__project__treestyle="nongnu")
    stores = stores.filter(file__startswith="/").only("file", "pootle_path")
    to_update = []
    for store in stores.iterator():
        lang, prj, d, fn = split_pootle_path(store.pootle_path)
        store.file = os.path.join(prj, lang, d, fn)
        to_update.append(store)
    if to_update:
        result = Batch(store_model, batch_size=500).update(
            to_update,
            update_fields=["file"],
            reduces=False)
        logger.debug("Cleaned %s store paths" % result)


def remove_fields_with_sql(apps, schema_editor):
    Unit = apps.get_model("pootle_store.Unit")
    cursor = schema_editor.connection.cursor()
    for col in REMOVED_UNIT_COLS:
        field = Unit._meta.get_field(col)
        if field.remote_field:
            fk_names = schema_editor._constraint_names(
                Unit, [field.column], foreign_key=True)
            for fk_name in fk_names:
                cursor.execute(
                    schema_editor._delete_constraint_sql(
                        schema_editor.sql_delete_fk, Unit, fk_name))
    cursor.execute(
        UNIT_DELETE_COLS_SQL
        % (", ".join(
            [("DROP COLUMN `%s`" % col)
             for col in REMOVED_UNIT_COLS])))


def remove_fields(apps, schema_editor):
    if schema_editor.connection.vendor == "mysql" and settings.POOTLE_SQL_MIGRATIONS:
        remove_fields_with_sql(apps, schema_editor)


class RemoveFieldIfExists(migrations.RemoveField):

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        if schema_editor.connection.vendor == "mysql" and settings.POOTLE_SQL_MIGRATIONS:
            return
        super(RemoveFieldIfExists, self).database_forwards(
            app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    replaces = [
        (b'pootle_store', '0027_unit_created_by'),
        (b'pootle_store', '0028_set_created_by'),
        (b'pootle_store', '0029_unit_tablename'),
        (b'pootle_store', '0030_store_tablename'),
        (b'pootle_store', '0031_suggestion_tablename'),
        (b'pootle_store', '0032_qc_tablename'),
        (b'pootle_store', '0033_conditionally_remove_unit_created_by'),
        (b'pootle_store', '0034_unitsource'),
        (b'pootle_store', '0035_set_created_by_again'),
        (b'pootle_store', '0036_unitchange'),
        (b'pootle_store', '0037_unitsource_fields'),
        (b'pootle_store', '0038_suggestion_tmp_state'),
        (b'pootle_store', '0039_set_suggestion_tmp_state'),
        (b'pootle_store', '0040_remove_suggestion_state'),
        (b'pootle_store', '0041_suggestionstate'),
        (b'pootle_store', '0042_add_default_suggestion_states'),
        (b'pootle_store', '0043_suggestion_state'),
        (b'pootle_store', '0044_set_new_suggestion_states'),
        (b'pootle_store', '0045_remove_suggestion_tmp_state'),
        (b'pootle_store', '0046_unit_source_one_to_one'),
        (b'pootle_store', '0047_remove_old_unit_fields'),
        (b'pootle_store', '0048_set_change_commented'),
        (b'pootle_store', '0049_remove_unit_commented'),
        (b'pootle_store', '0050_set_change_reviewed'),
        (b'pootle_store', '0051_remove_unit_reviewed'),
        (b'pootle_store', '0052_set_change_submitted'),
        (b'pootle_store', '0053_remove_unit_submitted'),
        (b'pootle_store', '0054_clean_abs_file_paths'),
        (b'pootle_store', '0055_fill_unit_source_data')]

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('pootle_store', '0026_suggestion_on_delete_user'),
        ('pootle_statistics', '0001_initial'),
    ]

    operations = [
        migrations.AlterModelTable(
            name='unit',
            table='pootle_store_unit',
        ),
        migrations.AlterModelTable(
            name='store',
            table='pootle_store_store',
        ),
        migrations.AlterModelTable(
            name='suggestion',
            table='pootle_store_suggestion',
        ),
        migrations.AlterModelTable(
            name='qualitycheck',
            table='pootle_store_qualitycheck',
        ),
        migrations.CreateModel(
            name='UnitSource',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_with', models.IntegerField(db_index=True, default=5)),
                ('created_by', models.ForeignKey(default=pootle.core.user.get_system_user_id, on_delete=models.SET(pootle.core.user.get_system_user), related_name='created_units', to=settings.AUTH_USER_MODEL)),
                ('unit', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='unit_source', to='pootle_store.Unit')),
                ('source_hash', models.CharField(editable=False, max_length=32, null=True)),
                ('source_length', models.SmallIntegerField(default=0, editable=False)),
                ('source_wordcount', models.SmallIntegerField(default=0, editable=False)),
            ],
            options={
                'abstract': False,
                'db_table': 'pootle_store_unit_source',
            },
        ),
        migrations.CreateModel(
            name='UnitChange',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('changed_with', models.IntegerField(db_index=True)),
                ('submitted_on', models.DateTimeField(db_index=True, null=True)),
                ('commented_on', models.DateTimeField(db_index=True, null=True)),
                ('reviewed_on', models.DateTimeField(db_index=True, null=True)),
                ('commented_by', models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='units_commented', to=settings.AUTH_USER_MODEL)),
                ('reviewed_by', models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='units_reviewed', to=settings.AUTH_USER_MODEL)),
                ('submitted_by', models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='units_submitted', to=settings.AUTH_USER_MODEL)),
                ('unit', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='change', to='pootle_store.Unit')),
            ],
            options={
                'abstract': False,
                'db_table': 'pootle_store_unit_change',
            },
        ),
        migrations.RunPython(convert_unit_source_change),
        migrations.RunPython(
            remove_fields,
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='source_hash',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='source_length',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='source_wordcount',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='commented_by',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='commented_on',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='reviewed_by',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='reviewed_on',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='submitted_by',
        ),
        RemoveFieldIfExists(
            model_name='unit',
            name='submitted_on',
        ),
        migrations.AlterField(
            model_name='unitchange',
            name='commented_by',
            field=models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='commented', to=settings.AUTH_USER_MODEL),
        ),
        migrations.AlterField(
            model_name='unitchange',
            name='reviewed_by',
            field=models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='reviewed', to=settings.AUTH_USER_MODEL),
        ),
        migrations.AlterField(
            model_name='unitchange',
            name='submitted_by',
            field=models.ForeignKey(null=True, on_delete=models.SET(pootle.core.user.get_system_user), related_name='submitted', to=settings.AUTH_USER_MODEL),
        ),
        migrations.CreateModel(
            name='SuggestionState',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(db_index=True, max_length=16)),
            ],
            options={
                'abstract': False,
                'db_table': 'pootle_store_suggestion_state',
            },
        ),
        migrations.RunPython(add_default_suggestion_states),
        migrations.RenameField(
            model_name='suggestion',
            old_name="state",
            new_name="tmp_state"),
        migrations.AddField(
            model_name='suggestion',
            name='state',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='suggestions', to='pootle_store.SuggestionState'),
        ),
        migrations.RunPython(set_suggestion_states),
        migrations.RemoveField(
            model_name='suggestion',
            name='tmp_state',
        ),
        migrations.RunPython(clean_abs_file_paths)]
