using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Migrations
{
    /// <inheritdoc />
    public partial class MigrateParametersToJsonSchema : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            // Convert legacy flat-shape parameter / return JSON in TemplateScripts,
            // SharedScripts, and ApiMethods to JSON Schema.
            //
            //   Parameters  [{name,type,required,itemType?}]
            //     →  {"type":"object","properties":{<name>:{"type":<jsType>}},"required":[...]}
            //
            //   Return      {type,itemType?}
            //     →  {"type":<jsType>} or {"type":"array","items":{"type":<inner>}}
            //
            // Idempotent: only rows whose value starts with '[' (parameters) or that
            // contain the legacy 'List' sentinel (return) are touched. Already-converted
            // rows are skipped.

            migrationBuilder.Sql(@"
IF OBJECT_ID('dbo.fn_LegacyTypeToJsonSchemaType', 'FN') IS NOT NULL
    DROP FUNCTION dbo.fn_LegacyTypeToJsonSchemaType;
");

            migrationBuilder.Sql(@"
CREATE FUNCTION dbo.fn_LegacyTypeToJsonSchemaType(@legacy NVARCHAR(50))
RETURNS NVARCHAR(50)
AS
BEGIN
    RETURN
        CASE LOWER(ISNULL(@legacy, 'string'))
            WHEN 'boolean'  THEN 'boolean'
            WHEN 'bool'     THEN 'boolean'
            WHEN 'integer'  THEN 'integer'
            WHEN 'int'      THEN 'integer'
            WHEN 'int32'    THEN 'integer'
            WHEN 'int64'    THEN 'integer'
            WHEN 'float'    THEN 'number'
            WHEN 'double'   THEN 'number'
            WHEN 'decimal'  THEN 'number'
            WHEN 'number'   THEN 'number'
            WHEN 'string'   THEN 'string'
            WHEN 'datetime' THEN 'string'
            WHEN 'object'   THEN 'object'
            WHEN 'list'     THEN 'array'
            WHEN 'array'    THEN 'array'
            ELSE 'string'
        END;
END;
");

            migrationBuilder.Sql(@"
IF OBJECT_ID('dbo.fn_LegacyParametersToJsonSchema', 'FN') IS NOT NULL
    DROP FUNCTION dbo.fn_LegacyParametersToJsonSchema;
");

            migrationBuilder.Sql(@"
CREATE FUNCTION dbo.fn_LegacyParametersToJsonSchema(@legacy NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    IF @legacy IS NULL OR LTRIM(@legacy) = '' RETURN NULL;
    IF LEFT(LTRIM(@legacy), 1) <> '[' RETURN @legacy;  -- already schema-shaped

    DECLARE @props NVARCHAR(MAX) = (
        SELECT STRING_AGG(
            CONCAT(
                '""',
                STRING_ESCAPE(JSON_VALUE(p.value, '$.name'), 'json'),
                '"":',
                CASE
                    WHEN LOWER(ISNULL(JSON_VALUE(p.value, '$.type'), 'string')) IN ('list', 'array')
                        THEN CONCAT(
                            '{""type"":""array"",""items"":{""type"":""',
                            dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(p.value, '$.itemType')),
                            '""}}')
                    ELSE CONCAT(
                        '{""type"":""',
                        dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(p.value, '$.type')),
                        '""}')
                END),
            ',')
            WITHIN GROUP (ORDER BY p.[key])
        FROM OPENJSON(@legacy) p
        WHERE JSON_VALUE(p.value, '$.name') IS NOT NULL
          AND JSON_VALUE(p.value, '$.name') <> ''
    );

    DECLARE @required NVARCHAR(MAX) = (
        SELECT STRING_AGG(
            CONCAT('""', STRING_ESCAPE(JSON_VALUE(p.value, '$.name'), 'json'), '""'),
            ',')
            WITHIN GROUP (ORDER BY p.[key])
        FROM OPENJSON(@legacy) p
        WHERE JSON_VALUE(p.value, '$.name') IS NOT NULL
          AND JSON_VALUE(p.value, '$.name') <> ''
          AND LOWER(ISNULL(JSON_VALUE(p.value, '$.required'), 'true')) <> 'false'
    );

    RETURN
        '{""type"":""object"",""properties"":{' + ISNULL(@props, '') + '}'
        + CASE WHEN @required IS NULL OR @required = '' THEN ''
               ELSE ',""required"":[' + @required + ']'
          END
        + '}';
END;
");

            migrationBuilder.Sql(@"
IF OBJECT_ID('dbo.fn_LegacyReturnToJsonSchema', 'FN') IS NOT NULL
    DROP FUNCTION dbo.fn_LegacyReturnToJsonSchema;
");

            migrationBuilder.Sql(@"
CREATE FUNCTION dbo.fn_LegacyReturnToJsonSchema(@legacy NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    IF @legacy IS NULL OR LTRIM(@legacy) = '' RETURN NULL;
    IF LEFT(LTRIM(@legacy), 1) <> '{' RETURN @legacy;

    DECLARE @legacyType NVARCHAR(50) = JSON_VALUE(@legacy, '$.type');
    IF @legacyType IS NULL RETURN @legacy;

    -- Already JSON Schema (lowercase types, no itemType legacy sentinel): leave it.
    IF @legacyType IN ('boolean','integer','number','string','object','array')
        AND JSON_VALUE(@legacy, '$.itemType') IS NULL
        RETURN @legacy;

    IF LOWER(@legacyType) = 'list'
    BEGIN
        DECLARE @inner NVARCHAR(50) =
            dbo.fn_LegacyTypeToJsonSchemaType(JSON_VALUE(@legacy, '$.itemType'));
        RETURN CONCAT('{""type"":""array"",""items"":{""type"":""', @inner, '""}}');
    END;

    RETURN CONCAT('{""type"":""', dbo.fn_LegacyTypeToJsonSchemaType(@legacyType), '""}');
END;
");

            migrationBuilder.Sql(@"
UPDATE TemplateScripts
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
WHERE ParameterDefinitions IS NOT NULL
  AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';

UPDATE TemplateScripts
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
WHERE ReturnDefinition IS NOT NULL
  AND LEFT(LTRIM(ReturnDefinition), 1) = '{';

UPDATE SharedScripts
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
WHERE ParameterDefinitions IS NOT NULL
  AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';

UPDATE SharedScripts
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
WHERE ReturnDefinition IS NOT NULL
  AND LEFT(LTRIM(ReturnDefinition), 1) = '{';

UPDATE ApiMethods
SET ParameterDefinitions = dbo.fn_LegacyParametersToJsonSchema(ParameterDefinitions)
WHERE ParameterDefinitions IS NOT NULL
  AND LEFT(LTRIM(ParameterDefinitions), 1) = '[';

UPDATE ApiMethods
SET ReturnDefinition = dbo.fn_LegacyReturnToJsonSchema(ReturnDefinition)
WHERE ReturnDefinition IS NOT NULL
  AND LEFT(LTRIM(ReturnDefinition), 1) = '{';
");

            migrationBuilder.Sql(@"
DROP FUNCTION IF EXISTS dbo.fn_LegacyParametersToJsonSchema;
DROP FUNCTION IF EXISTS dbo.fn_LegacyReturnToJsonSchema;
DROP FUNCTION IF EXISTS dbo.fn_LegacyTypeToJsonSchemaType;
");
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            // Lossy: JSON Schema can express fields (descriptions, defaults, enums,
            // nested objects) that the legacy flat shape cannot represent. Reverse
            // migration is not supported.
            throw new System.NotSupportedException(
                "Reverse migration from JSON Schema to legacy flat shape is not supported because the conversion is lossy.");
        }
    }
}
