/*
 * Copyright 2025 The Backstage Authors
 *
 * 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.
 */

import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { Config } from '@backstage/config';

interface ResourceSpec {
  type: string;
  cpu: number;
  memory: number;
  storage: number;
  replicas?: number;
}

interface CalculatePriceInput {
  resources: ResourceSpec[];
  region?: string;
  duration?: number; // hours
  instanceType?: string;
  backupPlan?: string;
  additionalFeatures?: string[];
}

interface PriceBreakdown {
  resourceType: string;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
  description: string;
}

interface CalculatePriceOutput {
  totalCost: number;
  monthlyCost: number;
  breakdown: PriceBreakdown[];
  currency: string;
  region: string;
  estimatedAt: string;
}

export const createCalculatePriceAction = (config: Config) => {
  return createTemplateAction<CalculatePriceInput, CalculatePriceOutput>({
    id: 'tollgate:calculate-price',
    description: 'Calculates projected costs for resource specifications',
    schema: {
      input: {
        type: 'object',
        required: ['resources'],
        properties: {
          resources: {
            type: 'array',
            title: 'Resource Specifications',
            description: 'Array of resource specifications to calculate pricing for',
            items: {
              type: 'object',
              required: ['type', 'cpu', 'memory', 'storage'],
              properties: {
                type: {
                  type: 'string',
                  title: 'Resource Type',
                  description: 'Type of resource (e.g., web-app, database, worker)',
                },
                cpu: {
                  type: 'number',
                  title: 'CPU Cores',
                  description: 'Number of CPU cores required',
                  minimum: 0.1,
                },
                memory: {
                  type: 'number',
                  title: 'Memory (GB)',
                  description: 'Amount of memory in gigabytes',
                  minimum: 0.1,
                },
                storage: {
                  type: 'number',
                  title: 'Storage (GB)',
                  description: 'Amount of storage in gigabytes',
                  minimum: 0,
                },
                replicas: {
                  type: 'number',
                  title: 'Replicas',
                  description: 'Number of replicas/instances',
                  minimum: 1,
                  default: 1,
                },
              },
            },
          },
          region: {
            type: 'string',
            title: 'Region',
            description: 'Cloud region for deployment',
            default: 'us-east-1',
          },
          duration: {
            type: 'number',
            title: 'Duration (hours)',
            description: 'Duration in hours for cost calculation',
            minimum: 1,
            default: 720, // 30 days
          },
          instanceType: {
            type: 'string',
            title: 'Instance Type',
            description: 'Instance type modifier for pricing',
            enum: ['standard', 'optimized', 'high-memory', 'high-cpu'],
            default: 'standard',
          },
          backupPlan: {
            type: 'string',
            title: 'Backup Plan',
            description: 'Backup plan for additional cost',
            enum: ['none', 'basic', 'premium'],
            default: 'none',
          },
          additionalFeatures: {
            type: 'array',
            title: 'Additional Features',
            description: 'Additional features that incur costs',
            items: {
              type: 'string',
              enum: ['monitoring', 'logging', 'ssl-certificates', 'load-balancer'],
            },
          },
        },
      },
      output: {
        type: 'object',
        properties: {
          totalCost: {
            type: 'number',
            title: 'Total Cost',
            description: 'Total cost for the specified duration',
          },
          monthlyCost: {
            type: 'number',
            title: 'Monthly Cost',
            description: 'Estimated monthly cost',
          },
          breakdown: {
            type: 'array',
            title: 'Cost Breakdown',
            description: 'Detailed cost breakdown by resource',
            items: {
              type: 'object',
              properties: {
                resourceType: { type: 'string' },
                quantity: { type: 'number' },
                unitPrice: { type: 'number' },
                totalPrice: { type: 'number' },
                description: { type: 'string' },
              },
            },
          },
          currency: {
            type: 'string',
            title: 'Currency',
            description: 'Currency code (USD)',
          },
          region: {
            type: 'string',
            title: 'Region',
            description: 'Region used for pricing',
          },
          estimatedAt: {
            type: 'string',
            title: 'Estimated At',
            description: 'Timestamp when estimate was calculated',
          },
        },
      },
    },

    async handler(ctx) {
      const {
        resources,
        region = 'us-east-1',
        duration = 720, // 30 days
        instanceType = 'standard',
        backupPlan = 'none',
        additionalFeatures = [],
      } = ctx.input;

      ctx.logger.info(`Calculating price for ${resources.length} resources in ${region}`);

      try {
        // Get pricing configuration
        const pricingConfig = config.getOptionalConfig('tollgate.scaffolder.pricing');
        const cpuHourlyRate = pricingConfig?.getOptionalNumber('cpuHourlyRate') ?? 0.048;
        const memoryHourlyRate = pricingConfig?.getOptionalNumber('memoryHourlyRate') ?? 0.0067;
        const storageMonthlyRate = pricingConfig?.getOptionalNumber('storageMonthlyRate') ?? 0.10;
        
        const regionalMultipliers = pricingConfig?.getOptionalConfig('regionalMultipliers');
        const regionalMultiplier = regionalMultipliers?.getOptionalNumber(region) ?? 1.0;

        // Instance type multipliers
        const instanceTypeMultipliers: Record<string, number> = {
          standard: 1.0,
          optimized: 1.2,
          'high-memory': 1.5,
          'high-cpu': 1.3,
        };
        const instanceMultiplier = instanceTypeMultipliers[instanceType] || 1.0;

        const breakdown: PriceBreakdown[] = [];
        let totalCost = 0;

        // Calculate resource costs
        for (const resource of resources) {
          const replicas = resource.replicas || 1;
          
          // CPU cost
          const cpuCost = resource.cpu * cpuHourlyRate * duration * replicas * regionalMultiplier * instanceMultiplier;
          breakdown.push({
            resourceType: `${resource.type}-cpu`,
            quantity: resource.cpu * replicas,
            unitPrice: cpuHourlyRate * regionalMultiplier * instanceMultiplier,
            totalPrice: cpuCost,
            description: `CPU cores for ${resource.type} (${resource.cpu} cores × ${replicas} replicas × ${duration}h)`,
          });
          totalCost += cpuCost;

          // Memory cost
          const memoryCost = resource.memory * memoryHourlyRate * duration * replicas * regionalMultiplier * instanceMultiplier;
          breakdown.push({
            resourceType: `${resource.type}-memory`,
            quantity: resource.memory * replicas,
            unitPrice: memoryHourlyRate * regionalMultiplier * instanceMultiplier,
            totalPrice: memoryCost,
            description: `Memory for ${resource.type} (${resource.memory} GB × ${replicas} replicas × ${duration}h)`,
          });
          totalCost += memoryCost;

          // Storage cost (monthly rate converted to hourly for duration)
          const storageHourlyRate = storageMonthlyRate / 720; // Convert monthly to hourly
          const storageCost = resource.storage * storageHourlyRate * duration * replicas * regionalMultiplier;
          breakdown.push({
            resourceType: `${resource.type}-storage`,
            quantity: resource.storage * replicas,
            unitPrice: storageHourlyRate * regionalMultiplier,
            totalPrice: storageCost,
            description: `Storage for ${resource.type} (${resource.storage} GB × ${replicas} replicas × ${duration}h)`,
          });
          totalCost += storageCost;
        }

        // Add backup plan costs
        if (backupPlan !== 'none') {
          const backupMultipliers: Record<string, number> = {
            basic: 0.05, // 5% of resource cost
            premium: 0.15, // 15% of resource cost
          };
          const backupCost = totalCost * (backupMultipliers[backupPlan] || 0);
          breakdown.push({
            resourceType: 'backup',
            quantity: 1,
            unitPrice: backupCost,
            totalPrice: backupCost,
            description: `${backupPlan} backup plan`,
          });
          totalCost += backupCost;
        }

        // Add additional feature costs
        const featureCosts: Record<string, number> = {
          monitoring: 10, // $10/month
          logging: 15, // $15/month
          'ssl-certificates': 5, // $5/month
          'load-balancer': 25, // $25/month
        };

        for (const feature of additionalFeatures) {
          const featureMonthlyCost = featureCosts[feature] || 0;
          const featureCost = (featureMonthlyCost / 720) * duration; // Convert to hourly rate
          breakdown.push({
            resourceType: feature,
            quantity: 1,
            unitPrice: featureMonthlyCost / 720,
            totalPrice: featureCost,
            description: `${feature} feature`,
          });
          totalCost += featureCost;
        }

        // Calculate monthly cost (assuming 720 hours per month)
        const monthlyCost = (totalCost / duration) * 720;

        const output: CalculatePriceOutput = {
          totalCost: Math.round(totalCost * 100) / 100,
          monthlyCost: Math.round(monthlyCost * 100) / 100,
          breakdown,
          currency: 'USD',
          region,
          estimatedAt: new Date().toISOString(),
        };

        ctx.output('totalCost', output.totalCost);
        ctx.output('monthlyCost', output.monthlyCost);
        ctx.output('breakdown', output.breakdown);
        ctx.output('currency', output.currency);
        ctx.output('region', output.region);
        ctx.output('estimatedAt', output.estimatedAt);

        ctx.logger.info(`Price calculation completed: $${output.totalCost} total, $${output.monthlyCost}/month`);

      } catch (error) {
        ctx.logger.error('Price calculation failed:', error);
        throw error;
      }
    },
  });
};