# Copyright 2026 EcoFuture Technology Services LLC and contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Generated by Django 6.0.1 on 2026-01-14 12:22

import base64
import json
import pickle
from django.db import migrations


def is_pickle_data(value):
    """Checks if the value is pickle data in base64 format"""
    if not value:
        return False

    try:
        # Try to parse as JSON
        json.loads(value)
        return False  # Already JSON
    except (json.JSONDecodeError, TypeError, ValueError):
        pass

    try:
        # Try to decode as base64+pickle
        decoded = base64.b64decode(value.encode('ascii'))
        # Check if it looks like pickle (starts with pickle magic bytes)
        return decoded[:2] in [b'\x80\x02', b'\x80\x03', b'\x80\x04', b'\x80\x05']
    except Exception:
        return False


def convert_pickle_to_json(apps, schema_editor):
    """Converts constance data from pickle (base64) to JSON"""

    # Don't use apps.get_model, work directly with DB
    # because the model may change in the future
    db_alias = schema_editor.connection.alias
    cursor = schema_editor.connection.cursor()

    try:
        # Get all records
        cursor.execute('SELECT id, key, value FROM constance_constance')
        rows = cursor.fetchall()

        converted_count = 0
        skipped_count = 0
        error_count = 0

        for row_id, key, value in rows:
            try:
                # Check if conversion is needed
                if not is_pickle_data(value):
                    print(f'  Skipping {key} - not pickle or already JSON')
                    skipped_count += 1
                    continue

                # Decode base64
                try:
                    pickled_data = base64.b64decode(value.encode('ascii'))
                except Exception as e:
                    print(f'  ⚠ Base64 decode error for {key}: {e}')
                    error_count += 1
                    continue

                # Unpickle
                try:
                    unpickled_value = pickle.loads(pickled_data)
                except Exception as e:
                    print(f'  ⚠ Unpickle error for {key}: {e}')
                    error_count += 1
                    continue

                # Convert to JSON
                try:
                    json_value = json.dumps(unpickled_value, ensure_ascii=False)
                except (TypeError, ValueError) as e:
                    print(f'  ⚠ JSON serialization error for {key}: {e}')
                    error_count += 1
                    continue

                # Update in DB
                cursor.execute(
                    'UPDATE constance_constance SET value = %s WHERE id = %s',
                    [json_value, row_id]
                )

                print(
                    f'  ✓ Converted {key}: {type(unpickled_value).__name__} = {unpickled_value}'
                )
                converted_count += 1

            except Exception as e:
                print(f'  ✗ Unexpected error processing {key}: {e}')
                error_count += 1

        print(f'\n=== Conversion Summary ===')
        print(f'Converted: {converted_count}')
        print(f'Skipped: {skipped_count}')
        print(f'Errors: {error_count}')

        if error_count > 0:
            print(f'\n⚠ WARNING: There are errors! Check values manually.')

    except Exception as e:
        print(f'Critical migration error: {e}')
        raise


class Migration(migrations.Migration):

    dependencies = [
        ('core', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(
            convert_pickle_to_json,
            migrations.RunPython.noop,
        ),
    ]