/**
 * Update Azure Pricing Command
 *
 * Updates azure-pricing.json with latest pricing data
 */

import { writeFileSync, readFileSync, existsSync } from 'fs';
import { join, dirname } from 'path';
import chalk from 'chalk';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

/**
 * Get pricing file path
 * @returns {string} Path to azure-pricing.json
 */
function getPricingPath() {
  return join(__dirname, '..', '..', 'content', '.morph', 'config', 'azure-pricing.json');
}

/**
 * Get schema file path
 * @returns {string} Path to azure-pricing.schema.json
 */
function getSchemaPath() {
  return join(__dirname, '..', '..', 'content', '.morph', 'config', 'azure-pricing.schema.json');
}

/**
 * Validate pricing data against JSON schema
 * @param {Object} pricingData - Pricing data to validate
 * @returns {boolean} True if valid
 * @throws {Error} If validation fails
 */
function validatePricingData(pricingData) {
  const schemaPath = getSchemaPath();

  if (!existsSync(schemaPath)) {
    throw new Error(`Schema file not found: ${schemaPath}`);
  }

  const schema = JSON.parse(readFileSync(schemaPath, 'utf8'));

  const ajv = new Ajv();
  addFormats(ajv);
  const validate = ajv.compile(schema);

  const valid = validate(pricingData);

  if (!valid) {
    const errors = validate.errors.map(err => {
      return `  - ${err.instancePath || 'root'}: ${err.message}`;
    }).join('\n');
    throw new Error(`Pricing data validation failed:\n${errors}`);
  }

  return true;
}

/**
 * Update pricing for a specific resource type
 * @param {Object} options - Command options
 * @param {string} options.resourceType - Resource type (e.g., "Microsoft.Sql/servers/databases")
 * @param {string} options.sku - SKU name (e.g., "S0")
 * @param {number} options.price - Monthly price
 * @param {boolean} options.dryRun - Preview without saving
 * @param {boolean} options.validate - Validate after update
 */
export async function updateResourcePricing(options) {
  const { resourceType, sku, price, dryRun = false, validate = true } = options;

  const pricingPath = getPricingPath();

  if (!existsSync(pricingPath)) {
    console.log(chalk.red(`✗ Pricing file not found: ${pricingPath}`));
    process.exit(1);
  }

  // Load current pricing
  const pricingData = JSON.parse(readFileSync(pricingPath, 'utf8'));

  // Ensure resource type exists
  if (!pricingData.resources[resourceType]) {
    pricingData.resources[resourceType] = {};
    console.log(chalk.yellow(`  Creating new resource type: ${resourceType}`));
  }

  // Update SKU price
  const oldPrice = pricingData.resources[resourceType][sku];
  pricingData.resources[resourceType][sku] = price;

  // Update metadata
  pricingData.lastUpdated = new Date().toISOString();

  // Validate if requested
  if (validate) {
    try {
      validatePricingData(pricingData);
      console.log(chalk.green('✓ Validation passed'));
    } catch (err) {
      console.log(chalk.red(`✗ Validation failed: ${err.message}`));
      process.exit(1);
    }
  }

  // Show changes
  console.log(chalk.blue('\nChanges:'));
  console.log(`  ${resourceType}`);
  console.log(`    ${sku}: ${oldPrice !== undefined ? `$${oldPrice}` : 'NEW'} → $${price}/month`);

  // Save if not dry run
  if (!dryRun) {
    writeFileSync(pricingPath, JSON.stringify(pricingData, null, 2) + '\n', 'utf8');
    console.log(chalk.green(`\n✓ Updated ${pricingPath}`));
  } else {
    console.log(chalk.yellow('\n⚠ Dry run - no changes saved'));
  }
}

/**
 * Show current pricing
 * @param {Object} options - Command options
 * @param {string} options.resourceType - Optional resource type filter
 * @param {string} options.format - Output format (table or json)
 */
export async function showPricing(options) {
  const { resourceType = null, format = 'table' } = options;

  const pricingPath = getPricingPath();

  if (!existsSync(pricingPath)) {
    console.log(chalk.red(`✗ Pricing file not found: ${pricingPath}`));
    process.exit(1);
  }

  const pricingData = JSON.parse(readFileSync(pricingPath, 'utf8'));

  if (format === 'json') {
    console.log(JSON.stringify(resourceType ? pricingData.resources[resourceType] : pricingData, null, 2));
    return;
  }

  // Table format
  console.log(chalk.bold('\nAzure Pricing Table'));
  console.log(chalk.dim(`Region: ${pricingData.region} | Currency: ${pricingData.currency}`));
  console.log(chalk.dim(`Last Updated: ${pricingData.lastUpdated}`));
  console.log('');

  const resourceTypes = resourceType
    ? [resourceType]
    : Object.keys(pricingData.resources).sort();

  for (const type of resourceTypes) {
    if (!pricingData.resources[type]) {
      console.log(chalk.red(`✗ Resource type not found: ${type}`));
      continue;
    }

    console.log(chalk.cyan(type));

    const skus = Object.entries(pricingData.resources[type]).sort((a, b) => a[1] - b[1]);

    for (const [skuName, price] of skus) {
      const priceStr = price === 0 ? chalk.green('FREE') : `$${price.toFixed(2)}/month`;
      console.log(`  ${skuName.padEnd(20)} ${priceStr}`);
    }

    console.log('');
  }
}

/**
 * Validate pricing file
 */
export async function validatePricing() {
  const pricingPath = getPricingPath();

  if (!existsSync(pricingPath)) {
    console.log(chalk.red(`✗ Pricing file not found: ${pricingPath}`));
    process.exit(1);
  }

  const pricingData = JSON.parse(readFileSync(pricingPath, 'utf8'));

  console.log(chalk.blue('Validating pricing data...'));

  try {
    validatePricingData(pricingData);
    console.log(chalk.green('✓ Pricing data is valid'));

    // Show stats
    const resourceCount = Object.keys(pricingData.resources).length;
    const skuCount = Object.values(pricingData.resources).reduce((sum, skus) => sum + Object.keys(skus).length, 0);

    console.log(chalk.dim(`\nStats:`));
    console.log(chalk.dim(`  Resource types: ${resourceCount}`));
    console.log(chalk.dim(`  SKUs: ${skuCount}`));
  } catch (err) {
    console.log(chalk.red(`✗ Validation failed: ${err.message}`));
    process.exit(1);
  }
}
