<?php

namespace App\Support\Concerns;

trait InteractsWithODataTypes
{
    /**
     * @return array<string, array<string, string>>
     */
    protected static function odataTypeMap(): array
    {
        return [
            'deviceConfiguration' => [
                'windows' => '#microsoft.graph.windows10CustomConfiguration',
                'ios' => '#microsoft.graph.iosGeneralDeviceConfiguration',
                'android' => '#microsoft.graph.androidGeneralDeviceConfiguration',
                'macOS' => '#microsoft.graph.macOSGeneralDeviceConfiguration',
                'all' => '#microsoft.graph.deviceConfiguration',
            ],
            'groupPolicyConfiguration' => [
                'windows' => '#microsoft.graph.groupPolicyConfiguration',
                'all' => '#microsoft.graph.groupPolicyConfiguration',
            ],
            'settingsCatalogPolicy' => [
                'windows' => '#microsoft.graph.deviceManagementConfigurationPolicy',
                'all' => '#microsoft.graph.deviceManagementConfigurationPolicy',
            ],
            'windowsUpdateRing' => [
                'windows' => '#microsoft.graph.windowsUpdateForBusinessConfiguration',
                'all' => '#microsoft.graph.windowsUpdateForBusinessConfiguration',
            ],
            'windowsFeatureUpdateProfile' => [
                'windows' => '#microsoft.graph.windowsFeatureUpdateProfile',
                'all' => '#microsoft.graph.windowsFeatureUpdateProfile',
            ],
            'windowsQualityUpdateProfile' => [
                'windows' => '#microsoft.graph.windowsQualityUpdateProfile',
                'all' => '#microsoft.graph.windowsQualityUpdateProfile',
            ],
            'deviceCompliancePolicy' => [
                'windows' => '#microsoft.graph.windows10CompliancePolicy',
                'ios' => '#microsoft.graph.iosCompliancePolicy',
                'android' => '#microsoft.graph.androidCompliancePolicy',
                'macOS' => '#microsoft.graph.macOSCompliancePolicy',
                'all' => '#microsoft.graph.deviceCompliancePolicy',
            ],
            'appProtectionPolicy' => [
                'mobile' => '#microsoft.graph.targetedManagedAppProtection',
                'all' => '#microsoft.graph.targetedManagedAppProtection',
            ],
            'conditionalAccessPolicy' => [
                'all' => '#microsoft.graph.conditionalAccessPolicy',
            ],
            'deviceManagementScript' => [
                'windows' => '#microsoft.graph.deviceManagementScript',
            ],
            'deviceShellScript' => [
                'macOS' => '#microsoft.graph.deviceShellScript',
                'all' => '#microsoft.graph.deviceShellScript',
            ],
            'deviceHealthScript' => [
                'windows' => '#microsoft.graph.deviceHealthScript',
                'all' => '#microsoft.graph.deviceHealthScript',
            ],
            'termsAndConditions' => [
                'windows' => '#microsoft.graph.termsAndConditions',
                'all' => '#microsoft.graph.termsAndConditions',
            ],
            'deviceComplianceScript' => [
                'windows' => '#microsoft.graph.deviceComplianceScript',
                'all' => '#microsoft.graph.deviceComplianceScript',
            ],
            'enrollmentRestriction' => [
                'all' => '#microsoft.graph.deviceEnrollmentConfiguration',
            ],
            'deviceEnrollmentLimitConfiguration' => [
                'all' => '#microsoft.graph.deviceEnrollmentLimitConfiguration',
            ],
            'deviceEnrollmentPlatformRestrictionsConfiguration' => [
                'all' => '#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration',
            ],
            'deviceEnrollmentNotificationConfiguration' => [
                'all' => '#microsoft.graph.deviceEnrollmentNotificationConfiguration',
            ],
            'windowsAutopilotDeploymentProfile' => [
                'windows' => '#microsoft.graph.windowsAutopilotDeploymentProfile',
            ],
            'windowsEnrollmentStatusPage' => [
                'windows' => '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration',
            ],
            'endpointSecurityIntent' => [
                'windows' => '#microsoft.graph.deviceManagementIntent',
            ],
            'mobileApp' => [
                'all' => '#microsoft.graph.mobileApp',
            ],
        ];
    }

    public static function expectedODataType(?string $policyType, ?string $platform = null): ?string
    {
        if (! $policyType) {
            return null;
        }

        $map = static::odataTypeMap();
        $types = $map[$policyType] ?? null;

        if ($types === null) {
            return null;
        }

        $platformKey = $platform ?: 'all';

        return $types[$platformKey] ?? $types['all'] ?? null;
    }

    /**
     * @return array{matches: bool, expected: ?string, actual: ?string}
     */
    public static function validateODataType(array $snapshot, ?string $policyType = null, ?string $platform = null): array
    {
        $actual = $snapshot['@odata.type'] ?? null;
        $contractFamily = config("graph_contracts.types.$policyType.type_family", []);

        if ($actual && $policyType && in_array(strtolower($actual), array_map('strtolower', $contractFamily), true)) {
            return [
                'matches' => true,
                'expected' => $actual,
                'actual' => $actual,
            ];
        }

        $expected = static::expectedODataType($policyType, $platform);

        if ($expected === null || $actual === null) {
            return [
                'matches' => true,
                'expected' => $expected,
                'actual' => $actual,
            ];
        }

        return [
            'matches' => strcasecmp($actual, $expected) === 0,
            'expected' => $expected,
            'actual' => $actual,
        ];
    }

    public static function odataTypeWarning(array $snapshot, ?string $policyType = null, ?string $platform = null): ?string
    {
        $validation = static::validateODataType($snapshot, $policyType, $platform);

        if ($validation['matches']) {
            return null;
        }

        if (! $validation['expected'] || ! $validation['actual']) {
            return null;
        }

        return sprintf(
            '@odata.type mismatch: expected %s for %s, got %s',
            $validation['expected'],
            $policyType ?? 'policy',
            $validation['actual']
        );
    }
}
