import { WorkflowTemplate } from '../models/WorkflowTemplate';
import { WorkflowRequest } from '../models/WorkflowRequest';
import { ApprovalLevel } from '../models/ApprovalLevel';
import { TemplateFieldResolver, FormStepConfig } from './templateFieldResolver.service';
import logger from '../utils/logger';

/**
 * Enhanced Template Service
 * Handles template-based workflow operations with dynamic form configuration
 */
export class EnhancedTemplateService {
  private fieldResolver = new TemplateFieldResolver();

  /**
   * Get form configuration for a template with resolved user references
   */
  async getFormConfig(
    templateId: string,
    requestId?: string,
    currentUserId?: string
  ): Promise<FormStepConfig[]> {
    try {
      const template = await WorkflowTemplate.findByPk(templateId);
      if (!template) {
        throw new Error('Template not found');
      }

      const stepsConfig = (template.formStepsConfig || []) as FormStepConfig[];

      // If request exists, resolve user references
      if (requestId && currentUserId) {
        const request = await WorkflowRequest.findByPk(requestId, {
          include: [{ model: ApprovalLevel, as: 'approvalLevels' }]
        });
        if (request) {
          return await this.resolveStepsWithUserData(stepsConfig, request, currentUserId);
        }
      }

      return stepsConfig;
    } catch (error) {
      logger.error('[EnhancedTemplateService] Error getting form config:', error);
      throw error;
    }
  }

  /**
   * Resolve user references in all steps
   */
  private async resolveStepsWithUserData(
    steps: FormStepConfig[],
    request: WorkflowRequest,
    currentUserId: string
  ): Promise<FormStepConfig[]> {
    try {
      // Get all approvers for context
      const approvers = await ApprovalLevel.findAll({
        where: { requestId: request.requestId }
      });
      const approverMap = new Map(
        approvers.map(a => [a.levelNumber, a])
      );

      const resolvedSteps = await Promise.all(
        steps.map(async (step) => {
          const resolvedFields = await this.fieldResolver.resolveUserReferences(
            step,
            request,
            currentUserId,
            {
              currentLevel: request.currentLevel,
              approvers: approverMap
            }
          );

          // Merge resolved values into field defaults
          const enrichedFields = step.fields.map(field => ({
            ...field,
            defaultValue: resolvedFields[field.fieldId] || field.defaultValue
          }));

          return {
            ...step,
            fields: enrichedFields
          };
        })
      );

      return resolvedSteps;
    } catch (error) {
      logger.error('[EnhancedTemplateService] Error resolving steps:', error);
      return steps; // Return original steps on error
    }
  }

  /**
   * Validate and save form data for a step
   */
  async saveStepData(
    templateId: string,
    requestId: string,
    stepNumber: number,
    formData: Record<string, any>,
    userId: string
  ): Promise<void> {
    try {
      const template = await WorkflowTemplate.findByPk(templateId);
      if (!template) {
        throw new Error('Template not found');
      }

      const stepsConfig = (template.formStepsConfig || []) as FormStepConfig[];
      const stepConfig = stepsConfig.find(s => s.stepNumber === stepNumber);

      if (!stepConfig) {
        throw new Error(`Step ${stepNumber} not found in template`);
      }

      // Validate required fields
      this.validateStepData(stepConfig, formData);

      // Save to template-specific storage
      await this.saveToTemplateStorage(template.workflowType, requestId, stepNumber, formData);
    } catch (error) {
      logger.error('[EnhancedTemplateService] Error saving step data:', error);
      throw error;
    }
  }

  /**
   * Validate step data against configuration
   */
  private validateStepData(stepConfig: FormStepConfig, formData: Record<string, any>): void {
    for (const field of stepConfig.fields) {
      if (field.required && !formData[field.fieldId]) {
        throw new Error(`Field ${field.label} is required`);
      }

      // Apply validation rules
      if (field.validation && formData[field.fieldId]) {
        const value = formData[field.fieldId];
        if (field.validation.min !== undefined && value < field.validation.min) {
          throw new Error(`${field.label} must be at least ${field.validation.min}`);
        }
        if (field.validation.max !== undefined && value > field.validation.max) {
          throw new Error(`${field.label} must be at most ${field.validation.max}`);
        }
        if (field.validation.pattern) {
          const regex = new RegExp(field.validation.pattern);
          if (!regex.test(String(value))) {
            throw new Error(`${field.label} format is invalid`);
          }
        }
      }
    }
  }

  /**
   * Save to template-specific storage based on workflow type
   */
  private async saveToTemplateStorage(
    workflowType: string,
    requestId: string,
    stepNumber: number,
    formData: Record<string, any>
  ): Promise<void> {
    switch (workflowType) {
      case 'CLAIM_MANAGEMENT':
        await this.saveClaimManagementStepData(requestId, stepNumber, formData);
        break;
      default:
        // Generic storage for custom templates
        logger.warn(`[EnhancedTemplateService] No specific storage handler for workflow type: ${workflowType}`);
    }
  }

  /**
   * Save claim management step data
   */
  private async saveClaimManagementStepData(
    requestId: string,
    stepNumber: number,
    formData: Record<string, any>
  ): Promise<void> {
    const { DealerClaimDetails } = await import('../models/DealerClaimDetails');
    const { DealerProposalDetails } = await import('../models/DealerProposalDetails');
    const { DealerCompletionDetails } = await import('../models/DealerCompletionDetails');

    switch (stepNumber) {
      case 1:
        // Save to dealer_claim_details
        await DealerClaimDetails.upsert({
          requestId,
          activityName: formData.activity_name,
          activityType: formData.activity_type,
          dealerCode: formData.dealer_code,
          dealerName: formData.dealer_name,
          dealerEmail: formData.dealer_email,
          dealerPhone: formData.dealer_phone,
          dealerAddress: formData.dealer_address,
          activityDate: formData.activity_date,
          location: formData.location,
          periodStartDate: formData.period_start_date,
          periodEndDate: formData.period_end_date,
          estimatedBudget: formData.estimated_budget,
        });
        break;
      case 2:
        // Save to dealer_proposal_details
        await DealerProposalDetails.upsert({
          requestId,
          costBreakup: formData.cost_breakup,
          totalEstimatedBudget: formData.total_estimated_budget,
          timelineMode: formData.timeline_mode,
          expectedCompletionDate: formData.expected_completion_date,
          expectedCompletionDays: formData.expected_completion_days,
          dealerComments: formData.dealer_comments,
          proposalDocumentPath: formData.proposal_document_path,
          proposalDocumentUrl: formData.proposal_document_url,
          submittedAt: new Date(),
        });
        break;
      case 5:
        // Save to dealer_completion_details
        await DealerCompletionDetails.upsert({
          requestId,
          activityCompletionDate: formData.activity_completion_date,
          numberOfParticipants: formData.number_of_participants,
          closedExpenses: formData.closed_expenses,
          totalClosedExpenses: formData.total_closed_expenses,
          completionDocuments: formData.completion_documents,
          activityPhotos: formData.activity_photos,
          submittedAt: new Date(),
        });
        break;
      default:
        logger.warn(`[EnhancedTemplateService] No storage handler for claim management step ${stepNumber}`);
    }
  }
}

