CREATE OR REPLACE FUNCTION public.__migration_115_safe_legacy_metadata_jsonb(input_text TEXT)
RETURNS JSONB
LANGUAGE plpgsql
AS $$
DECLARE
    parsed JSONB;
BEGIN
    IF input_text IS NULL OR BTRIM(input_text) = '' THEN
        RETURN '{}'::jsonb;
    END IF;

    BEGIN
        parsed := input_text::jsonb;
    EXCEPTION
        WHEN OTHERS THEN
            RETURN '{}'::jsonb;
    END;

    IF jsonb_typeof(parsed) = 'object' THEN
        RETURN parsed;
    END IF;

    RETURN jsonb_build_object('_legacy_metadata_raw_json', parsed);
END;
$$;

DO $$
BEGIN
    IF to_regclass('public.user_external_identities') IS NULL THEN
        RETURN;
    END IF;

    EXECUTE $sql$
INSERT INTO auth_identities (
    user_id,
    provider_type,
    provider_key,
    provider_subject,
    verified_at,
    metadata
)
SELECT
    legacy.user_id,
    'linuxdo',
    'linuxdo',
    legacy.provider_user_id,
    COALESCE(legacy.updated_at, legacy.created_at, NOW()),
    legacy.metadata_json || jsonb_build_object(
        'legacy_identity_id', legacy.id,
        'provider_user_id', legacy.provider_user_id,
        'provider_username', legacy.provider_username,
        'display_name', legacy.display_name,
        'migration', '115_auth_identity_legacy_external_backfill'
    )
FROM (
    SELECT
        uei.id,
        uei.user_id,
        BTRIM(uei.provider_user_id) AS provider_user_id,
        BTRIM(uei.provider_username) AS provider_username,
        BTRIM(uei.display_name) AS display_name,
        public.__migration_115_safe_legacy_metadata_jsonb(uei.metadata) AS metadata_json,
        uei.created_at,
        uei.updated_at
    FROM user_external_identities AS uei
    JOIN users AS u ON u.id = uei.user_id
    WHERE u.deleted_at IS NULL
      AND LOWER(BTRIM(COALESCE(uei.provider, ''))) = 'linuxdo'
      AND BTRIM(COALESCE(uei.provider_user_id, '')) <> ''
) AS legacy
ON CONFLICT (provider_type, provider_key, provider_subject) DO NOTHING;
$sql$;

    EXECUTE $sql$
INSERT INTO auth_identities (
    user_id,
    provider_type,
    provider_key,
    provider_subject,
    verified_at,
    metadata
)
SELECT
    legacy.user_id,
    'wechat',
    'wechat-main',
    legacy.provider_union_id,
    COALESCE(legacy.updated_at, legacy.created_at, NOW()),
    legacy.metadata_json || jsonb_build_object(
        'legacy_identity_id', legacy.id,
        'openid', legacy.provider_user_id,
        'unionid', legacy.provider_union_id,
        'provider_user_id', legacy.provider_user_id,
        'provider_union_id', legacy.provider_union_id,
        'provider_username', legacy.provider_username,
        'display_name', legacy.display_name,
        'migration', '115_auth_identity_legacy_external_backfill'
    )
FROM (
    SELECT
        uei.id,
        uei.user_id,
        BTRIM(uei.provider_user_id) AS provider_user_id,
        BTRIM(uei.provider_union_id) AS provider_union_id,
        BTRIM(uei.provider_username) AS provider_username,
        BTRIM(uei.display_name) AS display_name,
        public.__migration_115_safe_legacy_metadata_jsonb(uei.metadata) AS metadata_json,
        uei.created_at,
        uei.updated_at
    FROM user_external_identities AS uei
    JOIN users AS u ON u.id = uei.user_id
    WHERE u.deleted_at IS NULL
      AND LOWER(BTRIM(COALESCE(uei.provider, ''))) = 'wechat'
      AND BTRIM(COALESCE(uei.provider_union_id, '')) <> ''
) AS legacy
ON CONFLICT (provider_type, provider_key, provider_subject) DO NOTHING;
$sql$;

    EXECUTE $sql$
INSERT INTO auth_identity_channels (
    identity_id,
    provider_type,
    provider_key,
    channel,
    channel_app_id,
    channel_subject,
    metadata
)
SELECT
    ai.id,
    'wechat',
    'wechat-main',
    legacy.channel,
    legacy.channel_app_id,
    legacy.provider_user_id,
    legacy.metadata_json || jsonb_build_object(
        'openid', legacy.provider_user_id,
        'unionid', legacy.provider_union_id,
        'migration', '115_auth_identity_legacy_external_backfill'
    )
FROM (
    SELECT
        uei.user_id,
        BTRIM(uei.provider_user_id) AS provider_user_id,
        BTRIM(uei.provider_union_id) AS provider_union_id,
        BTRIM(COALESCE(meta.metadata_json ->> 'channel', '')) AS channel,
        BTRIM(COALESCE(meta.metadata_json ->> 'channel_app_id', meta.metadata_json ->> 'appid', meta.metadata_json ->> 'app_id', '')) AS channel_app_id,
        meta.metadata_json
    FROM user_external_identities AS uei
    JOIN users AS u ON u.id = uei.user_id
    CROSS JOIN LATERAL (
        SELECT public.__migration_115_safe_legacy_metadata_jsonb(uei.metadata) AS metadata_json
    ) AS meta
    WHERE u.deleted_at IS NULL
      AND LOWER(BTRIM(COALESCE(uei.provider, ''))) = 'wechat'
      AND BTRIM(COALESCE(uei.provider_union_id, '')) <> ''
) AS legacy
JOIN auth_identities AS ai
  ON ai.user_id = legacy.user_id
 AND ai.provider_type = 'wechat'
 AND ai.provider_key = 'wechat-main'
 AND ai.provider_subject = legacy.provider_union_id
WHERE legacy.channel <> ''
  AND legacy.channel_app_id <> ''
  AND legacy.provider_user_id <> ''
ON CONFLICT DO NOTHING;
$sql$;

    EXECUTE $sql$
INSERT INTO auth_identity_migration_reports (report_type, report_key, details)
SELECT
    'wechat_openid_only_requires_remediation',
    'legacy_external_identity:' || legacy.id::text,
    legacy.metadata_json || jsonb_build_object(
        'legacy_identity_id', legacy.id,
        'user_id', legacy.user_id,
        'openid', legacy.provider_user_id,
        'reason', 'legacy user_external_identities row only has openid and cannot be canonicalized offline',
        'migration', '115_auth_identity_legacy_external_backfill'
    )
FROM (
    SELECT
        uei.id,
        uei.user_id,
        BTRIM(uei.provider_user_id) AS provider_user_id,
        public.__migration_115_safe_legacy_metadata_jsonb(uei.metadata) AS metadata_json
    FROM user_external_identities AS uei
    JOIN users AS u ON u.id = uei.user_id
    WHERE u.deleted_at IS NULL
      AND LOWER(BTRIM(COALESCE(uei.provider, ''))) = 'wechat'
      AND BTRIM(COALESCE(uei.provider_user_id, '')) <> ''
      AND BTRIM(COALESCE(uei.provider_union_id, '')) = ''
) AS legacy
ON CONFLICT (report_type, report_key) DO NOTHING;
$sql$;
END $$;

INSERT INTO auth_identity_migration_reports (report_type, report_key, details)
SELECT
    'wechat_openid_only_requires_remediation',
    'synthetic_auth_identity:' || ai.id::text,
    COALESCE(ai.metadata, '{}'::jsonb) || jsonb_build_object(
        'auth_identity_id', ai.id,
        'user_id', ai.user_id,
        'provider_subject', ai.provider_subject,
        'reason', 'synthetic wechat auth identity still lacks unionid metadata and needs remediation',
        'migration', '115_auth_identity_legacy_external_backfill'
    )
FROM auth_identities AS ai
WHERE ai.provider_type = 'wechat'
  AND COALESCE(ai.metadata ->> 'backfill_source', '') = 'synthetic_email'
  AND BTRIM(COALESCE(ai.metadata ->> 'unionid', '')) = ''
ON CONFLICT (report_type, report_key) DO NOTHING;

DROP FUNCTION IF EXISTS public.__migration_115_safe_legacy_metadata_jsonb(TEXT);
