import { expect, request as playwrightRequest, type APIRequestContext } from '@playwright/test'

type TokenResponse = {
  access_token: string
  refresh_token: string
  token_type: string
}

type TreeResponse = {
  id: string
  name: string
  description?: string | null
  tree_type: string
  tree_structure: Record<string, unknown>
}

type SessionResponse = {
  id: string
  tree_id: string
  started_at: string | null
  completed_at: string | null
  ticket_number: string | null
  client_name: string | null
}

type SessionShareResponse = {
  id: string
  session_id: string
  share_token: string
  share_name: string | null
  visibility: 'public' | 'account'
  is_active: boolean
}

const apiOrigin = process.env.PLAYWRIGHT_API_ORIGIN || 'http://127.0.0.1:8000'
const testEmail =
  process.env.PLAYWRIGHT_TEST_EMAIL || 'teamadmin@resolutionflow.example.com'
const testPassword =
  process.env.PLAYWRIGHT_TEST_PASSWORD || 'TestPass123!'

export async function createAuthenticatedApiContext() {
  const authRequest = await playwrightRequest.newContext()
  const authResponse = await authRequest.post(`${apiOrigin}/api/v1/auth/login/json`, {
    data: {
      email: testEmail,
      password: testPassword,
    },
  })

  expect(authResponse.ok()).toBeTruthy()

  const token = (await authResponse.json()) as TokenResponse
  await authRequest.dispose()

  return playwrightRequest.newContext({
    baseURL: `${apiOrigin}/api/v1/`,
    extraHTTPHeaders: {
      Authorization: `Bearer ${token.access_token}`,
      'Content-Type': 'application/json',
    },
  })
}

export async function disposeApiContext(api: APIRequestContext) {
  await api.dispose()
}

export function uniqueName(prefix: string) {
  return `${prefix} ${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}

export async function createTroubleshootingTree(
  api: APIRequestContext,
  overrides?: Partial<{
    name: string
    description: string
    question: string
    answerLabel: string
    alternateAnswerLabel: string
    solutionTitle: string
    solutionDescription: string
    alternateSolutionTitle: string
    alternateSolutionDescription: string
    ticketNumber: string
  }>,
) {
  const treeName = overrides?.name || uniqueName('Playwright Troubleshooting Flow')
  const question = overrides?.question || 'Can you reproduce the issue?'
  const answerLabel = overrides?.answerLabel || 'Yes'
  const alternateAnswerLabel = overrides?.alternateAnswerLabel || 'No'
  const solutionTitle = overrides?.solutionTitle || 'Apply the known fix'
  const solutionDescription = overrides?.solutionDescription || 'Run the standard remediation steps'
  const alternateSolutionTitle = overrides?.alternateSolutionTitle || 'Collect more details and escalate'
  const alternateSolutionDescription =
    overrides?.alternateSolutionDescription || 'Escalate with the collected troubleshooting evidence'

  const response = await api.post('trees', {
    data: {
      name: treeName,
      description: overrides?.description || 'Playwright-created troubleshooting flow',
      category: 'Playwright',
      tree_type: 'troubleshooting',
      tree_structure: {
        id: 'root',
        type: 'decision',
        question,
        options: [
          { id: 'opt-yes', label: answerLabel, next_node_id: 'fix-step' },
          { id: 'opt-no', label: alternateAnswerLabel, next_node_id: 'escalate-step' },
        ],
        children: [
          {
            id: 'fix-step',
            type: 'solution',
            title: solutionTitle,
            description: solutionDescription,
            solution: 'Issue resolved with standard steps',
          },
          {
            id: 'escalate-step',
            type: 'solution',
            title: alternateSolutionTitle,
            description: alternateSolutionDescription,
            solution: 'Escalate to the next support tier',
          },
        ],
      },
      status: 'published',
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as TreeResponse
}

export async function createProceduralTree(
  api: APIRequestContext,
  overrides?: Partial<{
    name: string
    description: string
    steps: Array<Record<string, unknown>>
    intake_form: Array<Record<string, unknown>>
  }>,
) {
  const treeName = overrides?.name || uniqueName('Playwright Procedural Flow')
  const steps = overrides?.steps || [
    {
      id: 'step-1',
      type: 'procedure_step',
      title: 'Verify the server is reachable',
      description: 'Ping the target server to confirm network connectivity.',
      content_type: 'action',
      commands: 'ping -c 4 $server_ip',
      expected_outcome: 'All 4 packets received with no packet loss.',
    },
    {
      id: 'step-2',
      type: 'procedure_step',
      title: 'Check the service status',
      description: 'Verify the target service is running.',
      content_type: 'verification',
      commands: 'systemctl status $service_name',
      expected_outcome: 'Service shows active (running).',
    },
    {
      id: 'step-3',
      type: 'procedure_step',
      title: 'Restart the service if needed',
      description: 'Restart the service and confirm it comes back up.',
      content_type: 'action',
      commands: 'sudo systemctl restart $service_name',
      expected_outcome: 'Service restarts successfully.',
    },
    { id: 'step-end', type: 'procedure_end', title: 'End' },
  ]
  const intakeForm = overrides?.intake_form || [
    {
      variable_name: 'server_ip',
      label: 'Server IP Address',
      field_type: 'text',
      required: true,
      placeholder: 'e.g., 10.1.50.22',
      display_order: 1,
    },
    {
      variable_name: 'service_name',
      label: 'Service Name',
      field_type: 'text',
      required: true,
      placeholder: 'e.g., nginx',
      display_order: 2,
    },
  ]

  const response = await api.post('trees', {
    data: {
      name: treeName,
      description: overrides?.description || 'Playwright-created procedural flow',
      category: 'Playwright',
      tree_type: 'procedural',
      tree_structure: { steps },
      intake_form: intakeForm,
      status: 'published',
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as TreeResponse
}

export async function createProceduralTreeWithFallbacks(
  api: APIRequestContext,
  overrides?: Partial<{ name: string }>,
) {
  const treeName = overrides?.name || uniqueName('Playwright Fallback Flow')

  const response = await api.post('trees', {
    data: {
      name: treeName,
      description: 'Procedural flow with fallback branches for Playwright testing',
      category: 'Playwright',
      tree_type: 'procedural',
      tree_structure: {
        steps: [
          {
            id: 'step-1',
            type: 'procedure_step',
            title: 'Clear the DNS cache',
            description: 'Flush the local DNS resolver cache.',
            content_type: 'action',
            commands: 'ipconfig /flushdns',
            expected_outcome: 'DNS cache flushed successfully.',
            fallback_steps: [
              {
                id: 'fb-1a',
                type: 'procedure_step',
                title: 'Restart DNS Client service',
                description: 'If flushing DNS did not help, restart the DNS Client service.',
              },
              {
                id: 'fb-1b',
                type: 'procedure_step',
                title: 'Check DNS server configuration',
                description: 'Verify the DNS server addresses are correct in network settings.',
              },
            ],
          },
          {
            id: 'step-2',
            type: 'procedure_step',
            title: 'Verify DNS resolution',
            description: 'Test that names resolve correctly.',
            content_type: 'verification',
            commands: 'nslookup google.com',
            expected_outcome: 'Name resolves to an IP address.',
          },
          { id: 'step-end', type: 'procedure_end', title: 'End' },
        ],
      },
      status: 'published',
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as TreeResponse
}

export async function createSession(
  api: APIRequestContext,
  treeId: string,
  overrides?: Partial<{
    ticket_number: string
    client_name: string
  }>,
) {
  const response = await api.post('sessions', {
    data: {
      tree_id: treeId,
      ticket_number: overrides?.ticket_number || `PW-${Date.now()}`,
      client_name: overrides?.client_name || 'Playwright Client',
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as SessionResponse
}

export async function completeSession(
  api: APIRequestContext,
  sessionId: string,
  overrides?: Partial<{
    outcome: 'resolved' | 'workaround' | 'escalated' | 'unresolved'
    outcome_notes: string
    next_steps: string
  }>,
) {
  const response = await api.post(`sessions/${sessionId}/complete`, {
    data: {
      outcome: overrides?.outcome || 'resolved',
      outcome_notes: overrides?.outcome_notes || 'Completed by Playwright',
      next_steps: overrides?.next_steps || 'No follow-up required',
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as SessionResponse
}

export async function createSessionShare(
  api: APIRequestContext,
  sessionId: string,
  overrides?: Partial<{
    visibility: 'public' | 'account'
    share_name: string
    expires_at: string
  }>,
) {
  const response = await api.post(`sessions/${sessionId}/shares`, {
    data: {
      visibility: overrides?.visibility || 'public',
      share_name: overrides?.share_name,
      expires_at: overrides?.expires_at,
    },
  })

  expect(response.ok()).toBeTruthy()
  return (await response.json()) as SessionShareResponse
}
