import { describe, it, expect } from 'vitest'
import React from 'react'
import { render } from '@testing-library/react-native'
import {
  Skeleton,
  WorkoutCardSkeleton,
  TrainerCardSkeleton,
  CollectionCardSkeleton,
  StatsCardSkeleton,
} from '@/src/shared/components/loading/Skeleton'

/**
 * Helper to extract the flattened style from a rendered tree node.
 * Style can be a single object or an array of objects.
 */
function flattenStyle(style: any): Record<string, any> {
  if (!style) return {}
  if (Array.isArray(style)) {
    return Object.assign({}, ...style.filter(Boolean))
  }
  return style
}

describe('Skeleton', () => {
  it('renders with default dimensions (snapshot)', () => {
    const { toJSON } = render(<Skeleton />)
    expect(toJSON()).toMatchSnapshot()
  })

  it('applies default width=100% and height=20', () => {
    const { toJSON } = render(<Skeleton />)
    const tree = toJSON()
    const style = flattenStyle(tree?.props?.style)
    expect(style.width).toBe('100%')
    expect(style.height).toBe(20)
  })

  it('applies custom width and height', () => {
    const { toJSON } = render(<Skeleton width={200} height={40} />)
    const tree = toJSON()
    const style = flattenStyle(tree?.props?.style)
    expect(style.width).toBe(200)
    expect(style.height).toBe(40)
  })

  it('applies percentage width', () => {
    const { toJSON } = render(<Skeleton width="70%" height={20} />)
    const tree = toJSON()
    const style = flattenStyle(tree?.props?.style)
    expect(style.width).toBe('70%')
    expect(style.height).toBe(20)
  })

  it('applies custom borderRadius', () => {
    const { toJSON } = render(<Skeleton borderRadius={40} />)
    const tree = toJSON()
    const style = flattenStyle(tree?.props?.style)
    expect(style.borderRadius).toBe(40)
  })

  it('merges custom style prop', () => {
    const customStyle = { marginTop: 10 }
    const { toJSON } = render(<Skeleton style={customStyle} />)
    const tree = toJSON()
    const style = flattenStyle(tree?.props?.style)
    expect(style.marginTop).toBe(10)
    // Should still have default dimensions
    expect(style.width).toBe('100%')
    expect(style.height).toBe(20)
  })

  it('renders shimmer overlay as a child element', () => {
    const { toJSON } = render(<Skeleton />)
    const tree = toJSON()
    // Root View should have at least one child (the shimmer Animated.View)
    expect(tree?.children).toBeDefined()
    expect(tree!.children!.length).toBeGreaterThanOrEqual(1)
  })

  it('uses theme overlay color for background', () => {
    const { toJSON } = render(<Skeleton />)
    const tree = toJSON()
    // The Skeleton renders a View with style array including backgroundColor.
    // Walk the style array (may be nested) to find backgroundColor.
    function findBackgroundColor(node: any): string | undefined {
      if (!node?.props?.style) return undefined
      const style = flattenStyle(node.props.style)
      if (style.backgroundColor) return style.backgroundColor
      // Check children
      if (node.children && Array.isArray(node.children)) {
        for (const child of node.children) {
          if (typeof child === 'object') {
            const found = findBackgroundColor(child)
            if (found) return found
          }
        }
      }
      return undefined
    }
    const bgColor = findBackgroundColor(tree)
    expect(bgColor).toBeDefined()
    expect(typeof bgColor).toBe('string')
  })
})

describe('WorkoutCardSkeleton', () => {
  it('renders correct structure (snapshot)', () => {
    const { toJSON } = render(<WorkoutCardSkeleton />)
    expect(toJSON()).toMatchSnapshot()
  })

  it('contains multiple Skeleton elements as children', () => {
    const { toJSON } = render(<WorkoutCardSkeleton />)
    const tree = toJSON()
    // WorkoutCardSkeleton has: image skeleton + title skeleton + row with 2 skeletons = 4 total
    // Count all View nodes (Skeleton renders as View)
    function countViews(node: any): number {
      if (!node) return 0
      let count = node.type === 'View' ? 1 : 0
      if (node.children && Array.isArray(node.children)) {
        for (const child of node.children) {
          if (typeof child === 'object') count += countViews(child)
        }
      }
      return count
    }
    // Should have at least 5 View nodes (card container + skeletons + content wrapper + row)
    expect(countViews(tree)).toBeGreaterThanOrEqual(5)
  })
})

describe('TrainerCardSkeleton', () => {
  it('renders correct structure (snapshot)', () => {
    const { toJSON } = render(<TrainerCardSkeleton />)
    expect(toJSON()).toMatchSnapshot()
  })

  it('contains circular avatar skeleton (borderRadius=40)', () => {
    const { toJSON } = render(<TrainerCardSkeleton />)
    // First Skeleton inside is the avatar: width=80, height=80, borderRadius=40
    function findCircleSkeleton(node: any): boolean {
      if (!node) return false
      if (node.type === 'View') {
        const style = flattenStyle(node.props?.style)
        if (style.width === 80 && style.height === 80 && style.borderRadius === 40) return true
      }
      if (node.children && Array.isArray(node.children)) {
        return node.children.some((child: any) => typeof child === 'object' && findCircleSkeleton(child))
      }
      return false
    }
    expect(findCircleSkeleton(toJSON())).toBe(true)
  })
})

describe('CollectionCardSkeleton', () => {
  it('renders correct structure (snapshot)', () => {
    const { toJSON } = render(<CollectionCardSkeleton />)
    expect(toJSON()).toMatchSnapshot()
  })
})

describe('StatsCardSkeleton', () => {
  it('renders correct structure (snapshot)', () => {
    const { toJSON } = render(<StatsCardSkeleton />)
    expect(toJSON()).toMatchSnapshot()
  })

  it('contains header row with two skeleton elements', () => {
    const { toJSON } = render(<StatsCardSkeleton />)
    const tree = toJSON()
    // StatsCardSkeleton has: card > statsHeader (row) + large skeleton
    // statsHeader has 2 children (title skeleton + icon skeleton)
    expect(tree?.children).toBeDefined()
    expect(tree!.children!.length).toBeGreaterThanOrEqual(2)
  })
})
