import { LEDPattern, LEDFrame } from "@/lib/contexts/SimulationContext"
import { getGridLayoutDescription } from "./gridMapping"

export interface CodeGenerationOptions {
  functionNumber?: number
  functionName?: string
  includeComments?: boolean
  optimizeCode?: boolean
  codeStyle?: 'modern' | 'native'
}

export function generateCppCode(
  pattern: LEDPattern,
  options: CodeGenerationOptions = {}
): string {
  const {
    functionNumber = 16,
    functionName = pattern.name.replace(/[^a-zA-Z0-9]/g, ''),
    includeComments = true,
    optimizeCode = true
  } = options

  const sanitizedName = functionName || 'CustomPattern'
  const totalChannels = pattern.settings.totalChannels

  let code = ''

  if (includeComments) {
    code += `/*\n`
    code += ` * Generated LED Pattern: ${pattern.name}\n`
    if (pattern.description) {
      code += ` * Description: ${pattern.description}\n`
    }
    code += ` * Total Frames: ${pattern.frames.length}\n`
    code += ` * Total Channels: ${totalChannels}\n`
    if (pattern.gridConfig) {
      code += ` * Grid Layout: ${getGridLayoutDescription(pattern.gridConfig)}\n`
    }
    code += ` * Generated by AutoLight V3 Pattern Builder\n`
    code += ` */\n`
  }

  code += `void BaseChannel::taskSequence${functionNumber}${sanitizedName}() {\n`

  if (includeComments) {
    code += `    // Direct BaseChannel LED control\n\n`
  } else {
    code += `    // Direct BaseChannel LED control\n`
  }

  const repeatCount = pattern.settings.repeatCount

  if (repeatCount > 1) {
    code += `    for (int repeat = 0; repeat < ${repeatCount}; repeat++) {\n`
  }

  const frames = pattern.settings.direction === 'reverse'
    ? [...pattern.frames].reverse()
    : pattern.frames

  frames.forEach((frame, frameIndex) => {
    if (includeComments) {
      const activeChannels = frame.channels.filter(Boolean).length
      code += `        // Frame ${frameIndex + 1}: ${activeChannels} channels ON`
      if (frame.label) {
        code += ` - ${frame.label}`
      }
      code += `\n`
    }

    if (optimizeCode) {
      code += generateOptimizedFrameCode(frame, totalChannels, repeatCount > 1 ? '        ' : '    ')
    } else {
      code += generateSimpleFrameCode(frame, totalChannels, repeatCount > 1 ? '        ' : '    ')
    }

    code += `${repeatCount > 1 ? '        ' : '    '}h.delay(${frame.delay});\n`

    if (includeComments && frameIndex < frames.length - 1) {
      code += `\n`
    }
  })

  if (pattern.settings.direction === 'alternate' && repeatCount > 1) {
    if (includeComments) {
      code += `\n        // Reverse direction\n`
    }
    const reversedFrames = [...pattern.frames].reverse()
    reversedFrames.forEach((frame, frameIndex) => {
      if (includeComments) {
        const activeChannels = frame.channels.filter(Boolean).length
        code += `        // Frame ${frameIndex + 1} (reverse): ${activeChannels} channels ON`
        if (frame.label) {
          code += ` - ${frame.label}`
        }
        code += `\n`
      }

      if (optimizeCode) {
        code += generateOptimizedFrameCode(frame, totalChannels, '        ')
      } else {
        code += generateSimpleFrameCode(frame, totalChannels, '        ')
      }

      code += `        h.delay(${frame.delay});\n`

      if (includeComments && frameIndex < reversedFrames.length - 1) {
        code += `\n`
      }
    })
  }

  if (repeatCount > 1) {
    code += `    }\n\n`
  } else {
    code += `\n`
  }

  if (includeComments) {
    code += `    // End pattern - turn off all channels\n`
  }
  code += `    h.allOff();\n`
  code += `}\n`

  return code
}

function generateOptimizedFrameCode(frame: LEDFrame, totalChannels: number, indent: string): string {
  let code = ''
  const channels = frame.channels

  // Check if all channels are the same state
  const allOn = channels.every(Boolean)
  const allOff = channels.every(ch => !ch)

  if (allOn) {
    code += `${indent}h.allOn();\n`
    return code
  }

  if (allOff) {
    code += `${indent}h.allOff();\n`
    return code
  }

  // Find consecutive ranges
  const ranges = findConsecutiveRanges(channels)

  if (ranges.length <= 3) {
    // Use ranges if there are few ranges
    ranges.forEach(range => {
      if (range.state) {
        if (range.start === range.end) {
          code += `${indent}h.set(${range.start}, HIGH);\n`
        } else {
          code += `${indent}h.setRange(${range.start}, ${range.end}, HIGH);\n`
        }
      }
    })

    // Turn off channels if needed
    const hasOnChannels = ranges.some(r => r.state)
    if (hasOnChannels) {
      const offRanges = ranges.filter(r => !r.state)
      if (offRanges.length > 0 && offRanges.length <= 3) {
        offRanges.forEach(range => {
          if (range.start === range.end) {
            code += `${indent}h.set(${range.start}, LOW);\n`
          } else {
            code += `${indent}h.setRange(${range.start}, ${range.end}, LOW);\n`
          }
        })
      }
    }
  } else {
    // Use individual channel setting for complex patterns
    code += generateSimpleFrameCode(frame, totalChannels, indent)
  }

  return code
}

function generateSimpleFrameCode(frame: LEDFrame, totalChannels: number, indent: string): string {
  let code = ''
  const channels = frame.channels

  // Set individual channels
  channels.forEach((isOn, channelIndex) => {
    const state = isOn ? 'HIGH' : 'LOW'
    code += `${indent}h.set(${channelIndex}, ${state});\n`
  })

  return code
}

interface ChannelRange {
  start: number
  end: number
  state: boolean
}

function findConsecutiveRanges(channels: boolean[]): ChannelRange[] {
  const ranges: ChannelRange[] = []
  let currentStart = 0
  let currentState = channels[0]

  for (let i = 1; i <= channels.length; i++) {
    if (i === channels.length || channels[i] !== currentState) {
      ranges.push({
        start: currentStart,
        end: i - 1,
        state: currentState
      })

      if (i < channels.length) {
        currentStart = i
        currentState = channels[i]
      }
    }
  }

  return ranges
}

export function getNextAvailableSequenceNumber(): number {
  // In a real implementation, this would check existing sequences
  // For now, return a reasonable starting number
  return 16
}

export function generateFunctionDeclaration(
  functionNumber: number,
  functionName: string
): string {
  const sanitizedName = functionName.replace(/[^a-zA-Z0-9]/g, '')
  return `void taskSequence${functionNumber}${sanitizedName}();`
}

export function generateModeMapping(
  functionNumber: number,
  functionName: string,
  modeNumber: number
): string {
  const sanitizedName = functionName.replace(/[^a-zA-Z0-9]/g, '')
  return `total_mode_[${modeNumber}] = &BaseChannel::taskSequence${functionNumber}${sanitizedName};`
}

export function generateNativeCppCode(
  pattern: LEDPattern,
  options: CodeGenerationOptions = {}
): string {
  const {
    functionNumber = 16,
    functionName = pattern.name.replace(/[^a-zA-Z0-9]/g, ''),
    includeComments = true,
    optimizeCode = true
  } = options

  const sanitizedName = functionName || 'CustomPattern'
  const totalChannels = pattern.settings.totalChannels

  let code = ''

  if (includeComments) {
    code += `/*\n`
    code += ` * Generated LED Pattern: ${pattern.name}\n`
    if (pattern.description) {
      code += ` * Description: ${pattern.description}\n`
    }
    code += ` * Total Frames: ${pattern.frames.length}\n`
    code += ` * Total Channels: ${totalChannels}\n`
    if (pattern.gridConfig) {
      code += ` * Grid Layout: ${getGridLayoutDescription(pattern.gridConfig)}\n`
    }
    code += ` * Generated by AutoLight V3 Pattern Builder (Native API)\n`
    code += ` */\n`
  }

  code += `void BaseChannel::taskSequence${functionNumber}${sanitizedName}() {\n`

  const repeatCount = pattern.settings.repeatCount

  if (repeatCount > 1) {
    code += `    for (int repeat = 0; repeat < ${repeatCount}; repeat++) {\n`
  }

  const frames = pattern.settings.direction === 'reverse'
    ? [...pattern.frames].reverse()
    : pattern.frames

  frames.forEach((frame, frameIndex) => {
    if (includeComments) {
      const activeChannels = frame.channels.filter(Boolean).length
      code += `        // Frame ${frameIndex + 1}: ${activeChannels} channels ON`
      if (frame.label) {
        code += ` - ${frame.label}`
      }
      code += `\n`
    }

    if (optimizeCode) {
      code += generateNativeOptimizedFrameCode(frame, totalChannels, repeatCount > 1 ? '        ' : '    ')
    } else {
      code += generateNativeSimpleFrameCode(frame, totalChannels, repeatCount > 1 ? '        ' : '    ')
    }

    const delayValue = frame.delay > 0 ? frame.delay : 'channel_data_.delay_time_'
    code += `${repeatCount > 1 ? '        ' : '    '}sleep(${delayValue});\n`

    if (includeComments && frameIndex < frames.length - 1) {
      code += `\n`
    }
  })

  if (pattern.settings.direction === 'alternate' && repeatCount > 1) {
    if (includeComments) {
      code += `\n        // Reverse direction\n`
    }
    const reversedFrames = [...pattern.frames].reverse()
    reversedFrames.forEach((frame, frameIndex) => {
      if (includeComments) {
        const activeChannels = frame.channels.filter(Boolean).length
        code += `        // Frame ${frameIndex + 1} (reverse): ${activeChannels} channels ON`
        if (frame.label) {
          code += ` - ${frame.label}`
        }
        code += `\n`
      }

      if (optimizeCode) {
        code += generateNativeOptimizedFrameCode(frame, totalChannels, '        ')
      } else {
        code += generateNativeSimpleFrameCode(frame, totalChannels, '        ')
      }

      const delayValue = frame.delay > 0 ? frame.delay : 'channel_data_.delay_time_'
      code += `        sleep(${delayValue});\n`

      if (includeComments && frameIndex < reversedFrames.length - 1) {
        code += `\n`
      }
    })
  }

  if (repeatCount > 1) {
    code += `    }\n\n`
  } else {
    code += `\n`
  }

  if (includeComments) {
    code += `    // End pattern - turn off all channels\n`
  }
  code += `    off();\n`
  code += `}\n`

  return code
}

function generateNativeOptimizedFrameCode(frame: LEDFrame, totalChannels: number, indent: string): string {
  let code = ''
  const channels = frame.channels

  const allOn = channels.every(Boolean)
  const allOff = channels.every(ch => !ch)

  if (allOn) {
    code += `${indent}on();\n`
    return code
  }

  if (allOff) {
    code += `${indent}off();\n`
    return code
  }

  const ranges = findConsecutiveRanges(channels)

  if (ranges.length <= 3) {
    ranges.forEach(range => {
      if (range.state) {
        if (range.start === range.end) {
          code += `${indent}set(config_data_ptr_->header.pin_ptr_[${range.start}], HIGH);\n`
        } else {
          code += `${indent}for (int i = ${range.start}; i <= ${range.end}; i++) {\n`
          code += `${indent}    set(config_data_ptr_->header.pin_ptr_[i], HIGH);\n`
          code += `${indent}}\n`
        }
      }
    })

    const hasOnChannels = ranges.some(r => r.state)
    if (hasOnChannels) {
      const offRanges = ranges.filter(r => !r.state)
      if (offRanges.length > 0 && offRanges.length <= 3) {
        offRanges.forEach(range => {
          if (range.start === range.end) {
            code += `${indent}set(config_data_ptr_->header.pin_ptr_[${range.start}], LOW);\n`
          } else {
            code += `${indent}for (int i = ${range.start}; i <= ${range.end}; i++) {\n`
            code += `${indent}    set(config_data_ptr_->header.pin_ptr_[i], LOW);\n`
            code += `${indent}}\n`
          }
        })
      }
    }
  } else {
    code += generateNativeSimpleFrameCode(frame, totalChannels, indent)
  }

  return code
}

function generateNativeSimpleFrameCode(frame: LEDFrame, totalChannels: number, indent: string): string {
  let code = ''
  const channels = frame.channels

  channels.forEach((isOn, channelIndex) => {
    const state = isOn ? 'HIGH' : 'LOW'
    code += `${indent}set(config_data_ptr_->header.pin_ptr_[${channelIndex}], ${state});\n`
  })

  return code
}