import { ref, computed, watch } from 'vue'

/**
 * Node Validation Composable
 * Provides comprehensive validation for process flow nodes and overall process structure
 */
export function useNodeValidation() {
  // Validation state
  const validationResults = ref(new Map())
  const isValidating = ref(false)
  const lastValidationTime = ref(null)

  // Validation configuration
  const validationConfig = ref({
    processStructure: {
      requireStartNode: true,
      requireEndNode: true,
      allowMultipleStarts: false
    },
    nodeConfiguration: {
      validateFormSelection: true,
      validateApiUrls: true,
      validateGatewayPaths: true,
      validateScriptContent: true,
      validateNotificationContent: true
    },
    flowLogic: {
      checkReachability: true,
      checkDeadEnds: true
    }
  })

  // Validation severity levels
  const SEVERITY = {
    ERROR: 'error',
    WARNING: 'warning',
    INFO: 'info'
  }

  /**
   * Validate individual node configuration
   */
  const validateNode = (node) => {
    const issues = []
    
    if (!node || !node.type) {
      issues.push({
        type: 'configuration',
        severity: SEVERITY.ERROR,
        message: 'Node is missing or has no type',
        nodeId: node?.id || 'unknown'
      })
      return issues
    }

    // Validate based on node type
    switch (node.type) {
      case 'form':
        validateFormNode(node, issues)
        break
      case 'api':
        validateApiNode(node, issues)
        break
      case 'gateway':
        validateGatewayNode(node, issues)
        break
      case 'script':
        validateScriptNode(node, issues)
        break
      case 'notification':
        validateNotificationNode(node, issues)
        break
      case 'businessRule':
        validateBusinessRuleNode(node, issues)
        break
      case 'html':
        validateHtmlNode(node, issues)
        break
      case 'subprocess':
        validateSubprocessNode(node, issues)
        break
      case 'start':
      case 'end':
        // Start and end nodes have minimal validation requirements
        validateBasicNode(node, issues)
        break
    }

    return issues
  }

  /**
   * Validate form node configuration
   */
  const validateFormNode = (node, issues) => {
    if (validationConfig.value.nodeConfiguration.validateFormSelection) {
      if (!node.data?.formId) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'Form node has no form selected',
          nodeId: node.id,
          recommendation: 'Select a form for this node to collect user input'
        })
      }

      if (!node.data?.formName) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.INFO,
          message: 'Form node has no display name',
          nodeId: node.id,
          recommendation: 'Add a display name for better process readability'
        })
      }
    }
  }

  /**
   * Validate API node configuration
   */
  const validateApiNode = (node, issues) => {
    if (validationConfig.value.nodeConfiguration.validateApiUrls) {
      if (!node.data?.apiUrl || node.data.apiUrl.trim() === '') {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.ERROR,
          message: 'API node has no URL configured',
          nodeId: node.id,
          recommendation: 'Configure the API endpoint URL'
        })
      }

      if (!node.data?.apiMethod) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'API node has no HTTP method specified',
          nodeId: node.id,
          recommendation: 'Specify the HTTP method (GET, POST, etc.)'
        })
      }

      // Validate URL format if present
      if (node.data?.apiUrl) {
        try {
          new URL(node.data.apiUrl)
        } catch {
          issues.push({
            type: 'configuration',
            severity: SEVERITY.ERROR,
            message: 'API node has invalid URL format',
            nodeId: node.id,
            recommendation: 'Ensure the URL is properly formatted (e.g., https://example.com/api)'
          })
        }
      }
    }
  }

  /**
   * Validate gateway node configuration
   */
  const validateGatewayNode = (node, issues) => {
    if (validationConfig.value.nodeConfiguration.validateGatewayPaths) {
      const conditions = node.data?.conditions || []
      
      if (conditions.length === 0) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'Gateway node has no conditions defined',
          nodeId: node.id,
          recommendation: 'Add conditions to control process flow branching'
        })
      }

      // Check for incomplete conditions
      conditions.forEach((condition, index) => {
        if (!condition.variable || !condition.operator || condition.value === undefined) {
          issues.push({
            type: 'configuration',
            severity: SEVERITY.WARNING,
            message: `Gateway condition ${index + 1} is incomplete`,
            nodeId: node.id,
            recommendation: 'Complete all condition fields (variable, operator, value)'
          })
        }
      })
    }
  }

  /**
   * Validate script node configuration
   */
  const validateScriptNode = (node, issues) => {
    if (validationConfig.value.nodeConfiguration.validateScriptContent) {
      if (!node.data?.code || node.data.code.trim() === '') {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'Script node has no code defined',
          nodeId: node.id,
          recommendation: 'Add JavaScript code to execute in this node'
        })
      }
    }
  }

  /**
   * Validate notification node configuration
   */
  const validateNotificationNode = (node, issues) => {
    if (validationConfig.value.nodeConfiguration.validateNotificationContent) {
      if (!node.data?.content || node.data.content.trim() === '') {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'Notification node has no content',
          nodeId: node.id,
          recommendation: 'Add message content for the notification'
        })
      }

      if (!node.data?.notificationType) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: 'Notification node has no type specified',
          nodeId: node.id,
          recommendation: 'Specify notification type (email, SMS, in-app)'
        })
      }
    }
  }

  /**
   * Validate business rule node configuration
   */
  const validateBusinessRuleNode = (node, issues) => {
    const rules = node.data?.rules || []
    
    if (rules.length === 0) {
      issues.push({
        type: 'configuration',
        severity: SEVERITY.WARNING,
        message: 'Business rule node has no rules defined',
        nodeId: node.id,
        recommendation: 'Add business rules to evaluate conditions'
      })
    }

    rules.forEach((rule, index) => {
      if (!rule.variable || !rule.operator || rule.value === undefined) {
        issues.push({
          type: 'configuration',
          severity: SEVERITY.WARNING,
          message: `Business rule ${index + 1} is incomplete`,
          nodeId: node.id,
          recommendation: 'Complete all rule fields (variable, operator, value)'
        })
      }
    })
  }

  /**
   * Validate HTML node configuration
   */
  const validateHtmlNode = (node, issues) => {
    if (!node.data?.htmlContent || node.data.htmlContent.trim() === '') {
      issues.push({
        type: 'configuration',
        severity: SEVERITY.WARNING,
        message: 'HTML node has no content',
        nodeId: node.id,
        recommendation: 'Add HTML content to display in this node'
      })
    }
  }

  /**
   * Validate subprocess node configuration
   */
  const validateSubprocessNode = (node, issues) => {
    if (!node.data?.subprocessId) {
      issues.push({
        type: 'configuration',
        severity: SEVERITY.WARNING,
        message: 'Subprocess node has no subprocess selected',
        nodeId: node.id,
        recommendation: 'Select a subprocess to execute'
      })
    }
  }

  /**
   * Validate basic node properties
   */
  const validateBasicNode = (node, issues) => {
    if (!node.label || node.label.trim() === '') {
      issues.push({
        type: 'configuration',
        severity: SEVERITY.INFO,
        message: 'Node has no label',
        nodeId: node.id,
        recommendation: 'Add a descriptive label for better readability'
      })
    }
  }

  /**
   * Validate overall process structure
   */
  const validateProcessStructure = (nodes, edges) => {
    const issues = []
    
    // Check for start nodes
    const startNodes = nodes.filter(node => node.type === 'start')
    if (validationConfig.value.processStructure.requireStartNode) {
      if (startNodes.length === 0) {
        issues.push({
          type: 'structure',
          severity: SEVERITY.ERROR,
          message: 'Process has no start node',
          nodeId: null,
          recommendation: 'Add a start node to define where the process begins'
        })
      } else if (startNodes.length > 1 && !validationConfig.value.processStructure.allowMultipleStarts) {
        issues.push({
          type: 'structure',
          severity: SEVERITY.WARNING,
          message: `Process has ${startNodes.length} start nodes`,
          nodeId: null,
          recommendation: 'Consider having only one start node for clearer process flow'
        })
      }
    }

    // Check for end nodes
    const endNodes = nodes.filter(node => node.type === 'end')
    if (validationConfig.value.processStructure.requireEndNode) {
      if (endNodes.length === 0) {
        issues.push({
          type: 'structure',
          severity: SEVERITY.WARNING,
          message: 'Process has no end node',
          nodeId: null,
          recommendation: 'Add an end node to properly conclude the process'
        })
      }
    }

    return issues
  }

  /**
   * Find nodes that are unreachable from start nodes
   */
  const findUnreachableNodes = (nodes, edges) => {
    if (!validationConfig.value.flowLogic.checkReachability) return []

    const startNodes = nodes.filter(n => n.type === 'start')
    if (startNodes.length === 0) return []

    const reachable = new Set()
    const queue = [...startNodes.map(n => n.id)]

    while (queue.length > 0) {
      const nodeId = queue.shift()
      if (reachable.has(nodeId)) continue

      reachable.add(nodeId)
      const outgoingEdges = edges.filter(e => e.source === nodeId)
      queue.push(...outgoingEdges.map(e => e.target))
    }

    const unreachableNodes = nodes.filter(n => !reachable.has(n.id))
    return unreachableNodes.map(node => ({
      type: 'flow',
      severity: SEVERITY.WARNING,
      message: 'Node is unreachable from start',
      nodeId: node.id,
      recommendation: 'Connect this node to the main process flow or remove it'
    }))
  }

  /**
   * Find nodes that cannot reach any end node (dead ends)
   */
  const findDeadEnds = (nodes, edges) => {
    if (!validationConfig.value.flowLogic.checkDeadEnds) return []

    const endNodes = nodes.filter(n => n.type === 'end')
    if (endNodes.length === 0) return []

    const canReachEnd = new Set()
    const queue = [...endNodes.map(n => n.id)]

    while (queue.length > 0) {
      const nodeId = queue.shift()
      if (canReachEnd.has(nodeId)) continue

      canReachEnd.add(nodeId)
      const incomingEdges = edges.filter(e => e.target === nodeId)
      queue.push(...incomingEdges.map(e => e.source))
    }

    const deadEndNodes = nodes.filter(n => n.type !== 'end' && !canReachEnd.has(n.id))
    return deadEndNodes.map(node => ({
      type: 'flow',
      severity: SEVERITY.WARNING,
      message: 'Node cannot reach any end node',
      nodeId: node.id,
      recommendation: 'Ensure this node has a path to an end node'
    }))
  }

  /**
   * Validate entire process (nodes + edges + structure)
   */
  const validateProcess = (nodes, edges) => {
    isValidating.value = true
    const allIssues = []

    try {
      // Clear previous results
      validationResults.value.clear()

      // Validate process structure
      const structureIssues = validateProcessStructure(nodes, edges)
      allIssues.push(...structureIssues)

      // Validate individual nodes
      nodes.forEach(node => {
        const nodeIssues = validateNode(node)
        allIssues.push(...nodeIssues)
      })

      // Validate flow logic
      const unreachableIssues = findUnreachableNodes(nodes, edges)
      const deadEndIssues = findDeadEnds(nodes, edges)
      allIssues.push(...unreachableIssues)
      allIssues.push(...deadEndIssues)

      // Group issues by node
      allIssues.forEach(issue => {
        const nodeId = issue.nodeId || 'process'
        if (!validationResults.value.has(nodeId)) {
          validationResults.value.set(nodeId, [])
        }
        validationResults.value.get(nodeId).push(issue)
      })

      lastValidationTime.value = new Date()
    } finally {
      isValidating.value = false
    }

    return allIssues
  }

  /**
   * Get validation results for a specific node
   */
  const getNodeValidation = (nodeId) => {
    return validationResults.value.get(nodeId) || []
  }

  /**
   * Get validation icon for a node
   */
  const getValidationIcon = (nodeId) => {
    const issues = getNodeValidation(nodeId)
    if (issues.length === 0) return null

    const hasError = issues.some(issue => issue.severity === SEVERITY.ERROR)
    const hasWarning = issues.some(issue => issue.severity === SEVERITY.WARNING)

    if (hasError) return 'material-symbols:error'
    if (hasWarning) return 'material-symbols:warning'
    return 'material-symbols:info'
  }

  /**
   * Get validation tooltip content for a node
   */
  const getValidationTooltip = (nodeId) => {
    const issues = getNodeValidation(nodeId)
    if (issues.length === 0) return null

    const lines = issues.map(issue => `• ${issue.message}`)
    return lines.join('\n')
  }

  /**
   * Check if a node has validation issues
   */
  const hasValidationIssues = (nodeId) => {
    return getNodeValidation(nodeId).length > 0
  }

  /**
   * Get overall validation status
   */
  const overallValidationStatus = computed(() => {
    let hasErrors = false
    let hasWarnings = false

    for (const issues of validationResults.value.values()) {
      for (const issue of issues) {
        if (issue.severity === SEVERITY.ERROR) hasErrors = true
        if (issue.severity === SEVERITY.WARNING) hasWarnings = true
      }
    }

    if (hasErrors) return 'error'
    if (hasWarnings) return 'warning'
    return 'valid'
  })

  /**
   * Get validation summary statistics
   */
  const validationSummary = computed(() => {
    let totalIssues = 0
    let errors = 0
    let warnings = 0
    let infos = 0

    for (const issues of validationResults.value.values()) {
      totalIssues += issues.length
      for (const issue of issues) {
        switch (issue.severity) {
          case SEVERITY.ERROR: errors++; break
          case SEVERITY.WARNING: warnings++; break
          case SEVERITY.INFO: infos++; break
        }
      }
    }

    return {
      totalIssues,
      errors,
      warnings,
      infos,
      isValid: totalIssues === 0
    }
  })

  /**
   * Clear validation results
   */
  const clearValidation = () => {
    validationResults.value.clear()
    lastValidationTime.value = null
  }

  /**
   * Update validation configuration
   */
  const updateValidationConfig = (newConfig) => {
    validationConfig.value = { ...validationConfig.value, ...newConfig }
  }

  return {
    // State
    validationResults,
    isValidating,
    lastValidationTime,
    validationConfig,

    // Methods
    validateNode,
    validateProcess,
    getNodeValidation,
    getValidationIcon,
    getValidationTooltip,
    hasValidationIssues,
    clearValidation,
    updateValidationConfig,

    // Computed
    overallValidationStatus,
    validationSummary,

    // Constants
    SEVERITY
  }
}