<template>
  <div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-5xl mx-4 max-h-[90vh] flex flex-col">
      <!-- Header -->
      <div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
        <div class="flex items-center gap-3">
          <Icon name="ic:outline-quiz" size="24" class="text-primary-600" />
          <h3 class="text-lg font-semibold text-gray-900 dark:text-white">Test Scripts</h3>
        </div>
        <rs-button
          variant="text"
          size="sm"
          @click="$emit('close')"
          class="p-2"
        >
          <Icon name="ic:outline-close" size="16" />
        </rs-button>
      </div>

      <!-- Content -->
      <div class="flex flex-1 overflow-hidden">
        <!-- Test Templates Sidebar -->
        <div class="w-80 border-r border-gray-200 dark:border-gray-700 p-4 bg-gray-50 dark:bg-gray-900 overflow-y-auto">
          <h4 class="font-medium text-gray-900 dark:text-white mb-4">Test Templates</h4>
          <div class="space-y-2">
            <button
              v-for="template in testTemplates"
              :key="template.id"
              @click="insertTemplate(template)"
              class="w-full text-left p-3 rounded-lg transition-colors border border-gray-200 dark:border-gray-700 hover:bg-white dark:hover:bg-gray-800"
            >
              <div class="font-medium text-gray-900 dark:text-white text-sm">{{ template.name }}</div>
              <div class="text-xs text-gray-500 dark:text-gray-400">{{ template.description }}</div>
            </button>
          </div>

          <!-- Quick Snippets -->
          <h5 class="font-medium text-gray-900 dark:text-white mt-6 mb-3">Quick Snippets</h5>
          <div class="space-y-1">
            <button
              v-for="snippet in quickSnippets"
              :key="snippet.id"
              @click="insertSnippet(snippet.code)"
              class="w-full text-left p-2 rounded text-xs bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
            >
              {{ snippet.name }}
            </button>
          </div>
        </div>

        <!-- Script Editor -->
        <div class="flex-1 flex flex-col">
          <!-- Toolbar -->
          <div class="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
            <div class="flex items-center gap-3">
              <rs-button variant="primary" size="sm" @click="runTests" :loading="isRunning">
                <Icon name="ic:outline-play-arrow" size="16" class="mr-1" />
                Run Tests
              </rs-button>
              <rs-button variant="secondary-outline" size="sm" @click="clearEditor">
                <Icon name="ic:outline-clear" size="16" class="mr-1" />
                Clear
              </rs-button>
              <rs-button variant="secondary-outline" size="sm" @click="formatCode">
                <Icon name="ic:outline-auto-fix-high" size="16" class="mr-1" />
                Format
              </rs-button>
            </div>
            <div class="text-sm text-gray-500 dark:text-gray-400">
              pm.* APIs available
            </div>
          </div>

          <!-- Code Editor -->
          <div class="flex-1 relative">
            <textarea
              ref="codeEditor"
              v-model="testScript"
              class="w-full h-full p-4 font-mono text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-white border-0 resize-none focus:outline-none"
              placeholder="// Write your test scripts here
// Example:
pm.test('Status code is 200', function () {
    pm.response.to.have.status(200);
});

pm.test('Response has expected properties', function () {
    const jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('data');
});

pm.test('Response time is less than 200ms', function () {
    pm.expect(pm.response.responseTime).to.be.below(200);
});"
              spellcheck="false"
            ></textarea>
          </div>
        </div>

        <!-- Results Panel -->
        <div class="w-96 border-l border-gray-200 dark:border-gray-700 flex flex-col bg-gray-50 dark:bg-gray-900">
          <div class="p-4 border-b border-gray-200 dark:border-gray-700">
            <h4 class="font-medium text-gray-900 dark:text-white flex items-center gap-2">
              <Icon name="ic:outline-assessment" size="16" />
              Test Results
            </h4>
          </div>
          
          <div class="flex-1 overflow-y-auto p-4">
            <div v-if="testResults.length === 0" class="text-center py-8 text-gray-500 dark:text-gray-400">
              <Icon name="ic:outline-quiz" size="48" class="mx-auto mb-4 opacity-50" />
              <p class="text-sm">No test results yet</p>
              <p class="text-xs mt-1">Click "Run Tests" to execute your scripts</p>
            </div>

            <div v-else class="space-y-3">
              <!-- Summary -->
              <div class="p-3 rounded-lg border" :class="[
                allTestsPassed ? 'bg-green-50 border-green-200 dark:bg-green-900/20 dark:border-green-800' : 'bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800'
              ]">
                <div class="font-medium" :class="[
                  allTestsPassed ? 'text-green-800 dark:text-green-200' : 'text-red-800 dark:text-red-200'
                ]">
                  {{ passedTests }}/{{ testResults.length }} tests passed
                </div>
                <div class="text-xs mt-1" :class="[
                  allTestsPassed ? 'text-green-600 dark:text-green-300' : 'text-red-600 dark:text-red-300'
                ]">
                  Execution time: {{ executionTime }}ms
                </div>
              </div>

              <!-- Individual Results -->
              <div class="space-y-2">
                <div
                  v-for="(result, index) in testResults"
                  :key="index"
                  class="p-3 rounded-lg border"
                  :class="[
                    result.passed 
                      ? 'bg-green-50 border-green-200 dark:bg-green-900/20 dark:border-green-800' 
                      : 'bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800'
                  ]"
                >
                  <div class="flex items-start gap-2">
                    <Icon 
                      :name="result.passed ? 'ic:outline-check-circle' : 'ic:outline-error'" 
                      size="16" 
                      class="flex-shrink-0 mt-0.5"
                      :class="[
                        result.passed ? 'text-green-500' : 'text-red-500'
                      ]"
                    />
                    <div class="flex-1 min-w-0">
                      <div class="font-medium text-sm" :class="[
                        result.passed 
                          ? 'text-green-800 dark:text-green-200' 
                          : 'text-red-800 dark:text-red-200'
                      ]">
                        {{ result.name }}
                      </div>
                      <div v-if="result.error" class="text-xs mt-1 text-red-600 dark:text-red-300 font-mono">
                        {{ result.error }}
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <!-- Console Output -->
              <div v-if="consoleOutput.length > 0" class="mt-4">
                <h5 class="font-medium text-gray-900 dark:text-white mb-2">Console Output</h5>
                <div class="bg-gray-900 text-green-400 p-3 rounded-lg font-mono text-xs space-y-1 max-h-32 overflow-y-auto">
                  <div v-for="(output, index) in consoleOutput" :key="index">
                    {{ output }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
const emit = defineEmits(['close'])
const { response, showNotification } = useApiPlatform()

// Test script state
const testScript = ref('')
const testResults = ref([])
const consoleOutput = ref([])
const isRunning = ref(false)
const executionTime = ref(0)

// Editor reference
const codeEditor = ref(null)

// Test templates
const testTemplates = [
  {
    id: 'status-check',
    name: 'Status Code Check',
    description: 'Check response status code',
    code: `pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});`
  },
  {
    id: 'json-schema',
    name: 'JSON Schema Validation',
    description: 'Validate response structure',
    code: `pm.test("Response has expected structure", function () {
    const jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('data');
    pm.expect(jsonData).to.have.property('status');
});`
  },
  {
    id: 'response-time',
    name: 'Response Time Check',
    description: 'Check response performance',
    code: `pm.test("Response time is less than 200ms", function () {
    pm.expect(pm.response.responseTime).to.be.below(200);
});`
  },
  {
    id: 'header-check',
    name: 'Header Validation',
    description: 'Check response headers',
    code: `pm.test("Content-Type header is present", function () {
    pm.response.to.have.header("Content-Type");
});

pm.test("Content-Type is application/json", function () {
    pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
});`
  },
  {
    id: 'data-validation',
    name: 'Data Validation',
    description: 'Validate response data',
    code: `pm.test("Response contains required fields", function () {
    const jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('id').that.is.a('number');
    pm.expect(jsonData).to.have.property('name').that.is.a('string');
    pm.expect(jsonData).to.have.property('email').that.matches(/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/);
});`
  }
]

// Quick snippets
const quickSnippets = [
  { id: 'test-block', name: 'pm.test()', code: 'pm.test("Test name", function () {\n    \n});' },
  { id: 'status-200', name: 'Status 200', code: 'pm.response.to.have.status(200);' },
  { id: 'json-data', name: 'Get JSON', code: 'const jsonData = pm.response.json();' },
  { id: 'response-time', name: 'Response Time', code: 'pm.expect(pm.response.responseTime).to.be.below(200);' },
  { id: 'header-check', name: 'Header Check', code: 'pm.response.to.have.header("Content-Type");' },
  { id: 'console-log', name: 'Console Log', code: 'console.log("Debug message");' }
]

// Computed properties
const allTestsPassed = computed(() => testResults.value.length > 0 && testResults.value.every(test => test.passed))
const passedTests = computed(() => testResults.value.filter(test => test.passed).length)

// Insert template
const insertTemplate = (template) => {
  const currentValue = testScript.value
  const newValue = currentValue ? currentValue + '\n\n' + template.code : template.code
  testScript.value = newValue
  nextTick(() => {
    codeEditor.value?.focus()
  })
}

// Insert snippet
const insertSnippet = (code) => {
  const textarea = codeEditor.value
  if (!textarea) return

  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const currentValue = testScript.value
  
  const newValue = currentValue.substring(0, start) + code + currentValue.substring(end)
  testScript.value = newValue
  
  nextTick(() => {
    textarea.focus()
    textarea.setSelectionRange(start + code.length, start + code.length)
  })
}

// Clear editor
const clearEditor = () => {
  testScript.value = ''
  testResults.value = []
  consoleOutput.value = []
}

// Format code (basic formatting)
const formatCode = () => {
  try {
    // Basic formatting - add proper indentation
    const lines = testScript.value.split('\n')
    let indentLevel = 0
    const formatted = []
    
    for (const line of lines) {
      const trimmed = line.trim()
      if (trimmed.includes('}')) indentLevel--
      formatted.push('    '.repeat(Math.max(0, indentLevel)) + trimmed)
      if (trimmed.includes('{')) indentLevel++
    }
    
    testScript.value = formatted.join('\n')
    showNotification('Code formatted', 'success', 2000)
  } catch (error) {
    showNotification('Failed to format code', 'error')
  }
}

// Run test scripts
const runTests = async () => {
  if (!testScript.value.trim()) {
    showNotification('Please write some test scripts first', 'warning')
    return
  }

  if (!response.value || !response.value.status) {
    showNotification('No response data available to test', 'warning')
    return
  }

  isRunning.value = true
  testResults.value = []
  consoleOutput.value = []
  
  const startTime = Date.now()

  try {
    // Create pm object with response data
    const pm = createPmObject()
    
    // Create console object to capture output
    const console = {
      log: (...args) => {
        consoleOutput.value.push(args.join(' '))
      },
      error: (...args) => {
        consoleOutput.value.push('ERROR: ' + args.join(' '))
      },
      warn: (...args) => {
        consoleOutput.value.push('WARN: ' + args.join(' '))
      }
    }

    // Execute the test script in a controlled environment
    const testFunction = new Function('pm', 'console', 'expect', testScript.value)
    testFunction(pm, console, pm.expect)

    if (testResults.value.length === 0) {
      showNotification('No tests were executed. Make sure to use pm.test() functions.', 'warning')
    } else {
      const passed = testResults.value.filter(test => test.passed).length
      const total = testResults.value.length
      showNotification(`Test execution complete: ${passed}/${total} tests passed`, passed === total ? 'success' : 'warning')
    }

  } catch (error) {
    console.error('Test execution error:', error)
    testResults.value.push({
      name: 'Script Execution Error',
      passed: false,
      error: error.message
    })
    showNotification(`Test execution failed: ${error.message}`, 'error')
  } finally {
    executionTime.value = Date.now() - startTime
    isRunning.value = false
  }
}

// Create pm object similar to Postman
const createPmObject = () => {
  const pm = {
    response: {
      code: response.value.status,
      status: response.value.statusText || '',
      headers: new Map(Object.entries(response.value.headers || {})),
      responseTime: response.value.time || 0,
      responseSize: response.value.size || 0,
      text: () => {
        if (typeof response.value.data === 'string') return response.value.data
        return JSON.stringify(response.value.data)
      },
      json: () => {
        if (typeof response.value.data === 'object') return response.value.data
        if (typeof response.value.data === 'string') {
          try {
            return JSON.parse(response.value.data)
          } catch {
            throw new Error('Response is not valid JSON')
          }
        }
        throw new Error('Response is not JSON')
      },
      to: {
        have: {
          status: (expectedStatus) => {
            if (response.value.status !== expectedStatus) {
              throw new Error(`Expected status ${expectedStatus}, but got ${response.value.status}`)
            }
          },
          header: (headerName) => {
            if (!response.value.headers || !response.value.headers[headerName]) {
              throw new Error(`Expected header '${headerName}' not found`)
            }
          }
        }
      }
    },
    test: (name, testFunction) => {
      try {
        testFunction()
        testResults.value.push({
          name,
          passed: true,
          error: null
        })
      } catch (error) {
        testResults.value.push({
          name,
          passed: false,
          error: error.message
        })
      }
    },
    expect: (value) => {
      return {
        to: {
          equal: (expected) => {
            if (value !== expected) {
              throw new Error(`Expected ${expected}, but got ${value}`)
            }
          },
          be: {
            below: (threshold) => {
              if (value >= threshold) {
                throw new Error(`Expected ${value} to be below ${threshold}`)
              }
            },
            above: (threshold) => {
              if (value <= threshold) {
                throw new Error(`Expected ${value} to be above ${threshold}`)
              }
            },
            a: (type) => {
              if (typeof value !== type) {
                throw new Error(`Expected ${value} to be of type ${type}, but got ${typeof value}`)
              }
              return {
                that: {
                  matches: (regex) => {
                    if (!regex.test(value)) {
                      throw new Error(`Expected ${value} to match ${regex}`)
                    }
                  }
                }
              }
            }
          },
          have: {
            property: (prop) => {
              if (!value || typeof value !== 'object' || !(prop in value)) {
                throw new Error(`Expected object to have property '${prop}'`)
              }
              return {
                that: {
                  is: {
                    a: (type) => {
                      if (typeof value[prop] !== type) {
                        throw new Error(`Expected property '${prop}' to be of type ${type}`)
                      }
                      return {
                        that: {
                          matches: (regex) => {
                            if (!regex.test(value[prop])) {
                              throw new Error(`Expected property '${prop}' with value '${value[prop]}' to match ${regex}`)
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            length: (expectedLength) => {
              if (!value || value.length !== expectedLength) {
                throw new Error(`Expected length ${expectedLength}, but got ${value?.length || 0}`)
              }
            }
          },
          include: (substring) => {
            if (!value || !value.toString().includes(substring)) {
              throw new Error(`Expected '${value}' to include '${substring}'`)
            }
          }
        }
      }
    }
  }

  // Add header helpers
  pm.response.headers.get = (name) => {
    return response.value.headers?.[name] || response.value.headers?.[name.toLowerCase()]
  }

  return pm
}

// Load saved scripts on mount
onMounted(() => {
  const saved = localStorage.getItem('api-platform-test-scripts')
  if (saved) {
    testScript.value = saved
  }
})

// Save scripts when they change
watch(testScript, (newScript) => {
  localStorage.setItem('api-platform-test-scripts', newScript)
}, { debounce: 1000 })
</script> 