import { OnModuleInit } from '@nestjs/common';
import { Query, ResolveField, Resolver, Subscription } from '@nestjs/graphql';

import { AuthAction, Resource } from '@unraid/shared/graphql.model.js';
import { UsePermissions } from '@unraid/shared/use-permissions.directive.js';

import { pubsub, PUBSUB_CHANNEL } from '@app/core/pubsub.js';
import { CpuUtilization } from '@app/unraid-api/graph/resolvers/info/cpu/cpu.model.js';
import { CpuService } from '@app/unraid-api/graph/resolvers/info/cpu/cpu.service.js';
import { MemoryUtilization } from '@app/unraid-api/graph/resolvers/info/memory/memory.model.js';
import { MemoryService } from '@app/unraid-api/graph/resolvers/info/memory/memory.service.js';
import { Metrics } from '@app/unraid-api/graph/resolvers/metrics/metrics.model.js';
import { SubscriptionHelperService } from '@app/unraid-api/graph/services/subscription-helper.service.js';
import { SubscriptionTrackerService } from '@app/unraid-api/graph/services/subscription-tracker.service.js';

@Resolver(() => Metrics)
export class MetricsResolver implements OnModuleInit {
    constructor(
        private readonly cpuService: CpuService,
        private readonly memoryService: MemoryService,
        private readonly subscriptionTracker: SubscriptionTrackerService,
        private readonly subscriptionHelper: SubscriptionHelperService
    ) {}

    onModuleInit() {
        // Register CPU polling with 1 second interval
        this.subscriptionTracker.registerTopic(
            PUBSUB_CHANNEL.CPU_UTILIZATION,
            async () => {
                const payload = await this.cpuService.generateCpuLoad();
                pubsub.publish(PUBSUB_CHANNEL.CPU_UTILIZATION, { systemMetricsCpu: payload });
            },
            1000
        );

        // Register memory polling with 2 second interval
        this.subscriptionTracker.registerTopic(
            PUBSUB_CHANNEL.MEMORY_UTILIZATION,
            async () => {
                const payload = await this.memoryService.generateMemoryLoad();
                pubsub.publish(PUBSUB_CHANNEL.MEMORY_UTILIZATION, { systemMetricsMemory: payload });
            },
            2000
        );
    }

    @Query(() => Metrics)
    @UsePermissions({
        action: AuthAction.READ_ANY,
        resource: Resource.INFO,
    })
    public async metrics(): Promise<Partial<Metrics>> {
        return {
            id: 'metrics',
        };
    }

    @ResolveField(() => CpuUtilization, { nullable: true })
    public async cpu(): Promise<CpuUtilization> {
        return this.cpuService.generateCpuLoad();
    }

    @ResolveField(() => MemoryUtilization, { nullable: true })
    public async memory(): Promise<MemoryUtilization> {
        return this.memoryService.generateMemoryLoad();
    }

    @Subscription(() => CpuUtilization, {
        name: 'systemMetricsCpu',
        resolve: (value) => value.systemMetricsCpu,
    })
    @UsePermissions({
        action: AuthAction.READ_ANY,
        resource: Resource.INFO,
    })
    public async systemMetricsCpuSubscription() {
        return this.subscriptionHelper.createTrackedSubscription(PUBSUB_CHANNEL.CPU_UTILIZATION);
    }

    @Subscription(() => MemoryUtilization, {
        name: 'systemMetricsMemory',
        resolve: (value) => value.systemMetricsMemory,
    })
    @UsePermissions({
        action: AuthAction.READ_ANY,
        resource: Resource.INFO,
    })
    public async systemMetricsMemorySubscription() {
        return this.subscriptionHelper.createTrackedSubscription(PUBSUB_CHANNEL.MEMORY_UTILIZATION);
    }
}
