"use client"

import { useState, useEffect, useCallback, useRef } from "react"
import type React from "react"
import { cn } from "@/lib/utils"
import { useTheme } from "next-themes"
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
import { Copy, Check, Settings, ChevronDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Switch } from "@/components/ui/switch"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"

interface ComponentProperty {
  name: string
  type: "select" | "boolean" | "text" | "textarea" | "number"
  options?: string[]
  defaultValue: any
  label: string
  description?: string
  placeholder?: string
}

interface ComponentContainerProps {
  title?: string
  description?: string
  code?: string
  children: React.ReactNode
  className?: string
  defaultTab?: "preview" | "code"
  language?: string
  properties?: ComponentProperty[]
  renderComponent?: (props: Record<string, any>) => React.ReactNode
  generateCode?: (props: Record<string, any>) => string
}

interface Token {
  type: string
  content: string
  index: number
}

// Helper function to get display value from actual value
const getDisplayValue = (actualValue: string): string => {
  const displayMap: Record<string, string> = {
    default: "Primary", // Map default to Primary for button variant
    secondary: "Secondary",
    destructive: "Destructive",
    outline: "Outline",
    ghost: "Ghost",
    link: "Link",
    sm: "Small",
    lg: "Large",
    icon: "Icon",
    success: "Success",
    warning: "Warning",
    info: "Info",
    error: "Error",
    neutral: "Neutral",
    xl: "Extra Large",
    left: "Left",
    right: "Right",
    none: "None",
  }

  return displayMap[actualValue] || actualValue.charAt(0).toUpperCase() + actualValue.slice(1)
}

// Helper function to get actual value from display value
const getActualValue = (displayValue: string): string => {
  const valueMap: Record<string, string> = {
    Primary: "default", // Map Primary to default for button variant
    Default: "default",
    Secondary: "secondary",
    Destructive: "destructive",
    Outline: "outline",
    Ghost: "ghost",
    Link: "link",
    Small: "sm",
    Large: "lg",
    Icon: "icon",
    Success: "success",
    Warning: "warning",
    Info: "info",
    Error: "error",
    Neutral: "neutral",
    "Extra Large": "xl",
    Left: "left",
    Right: "right",
    None: "none",
  }

  return valueMap[displayValue] || displayValue.toLowerCase()
}

export function ComponentContainer({
  title = "",
  description,
  code = "",
  children,
  className,
  defaultTab = "preview",
  language = "tsx",
  properties = [],
  renderComponent,
  generateCode,
}: ComponentContainerProps) {
  const { theme } = useTheme()
  const [mounted, setMounted] = useState(false)
  const [copied, setCopied] = useState(false)
  const [showProperties, setShowProperties] = useState(false)
  const [componentProps, setComponentProps] = useState<Record<string, any>>({})

  // Use ref to track if we've initialized props to prevent infinite loops
  const initializedRef = useRef(false)
  const propertiesRef = useRef<ComponentProperty[]>([])

  // Initialize props with default values immediately
  useEffect(() => {
    // Check if properties have actually changed
    const propertiesChanged =
      properties.length !== propertiesRef.current.length ||
      properties.some((prop, index) => {
        const prevProp = propertiesRef.current[index]
        return (
          !prevProp ||
          prop.name !== prevProp.name ||
          prop.defaultValue !== prevProp.defaultValue ||
          prop.type !== prevProp.type
        )
      })

    if (!initializedRef.current || propertiesChanged) {
      const initialProps: Record<string, any> = {}
      properties.forEach((prop) => {
        // For select properties, we need to store the display value that matches the options
        if (prop.type === "select" && prop.options) {
          const displayValue = getDisplayValue(prop.defaultValue)
          // Make sure the display value exists in the options
          if (prop.options.includes(displayValue)) {
            initialProps[prop.name] = displayValue
          } else {
            // Fallback to the first option if display value not found
            initialProps[prop.name] = prop.options[0] || prop.defaultValue
          }
        } else {
          initialProps[prop.name] = prop.defaultValue
        }
      })

      setComponentProps(initialProps)
      propertiesRef.current = [...properties]
      initializedRef.current = true
    }
  }, [properties])

  useEffect(() => {
    setMounted(true)
  }, [])

  const copyToClipboard = useCallback(
    (textToCopy?: string) => {
      const finalCode = textToCopy || (generateCode ? generateCode(componentProps) : code)
      navigator.clipboard.writeText(finalCode || "")
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    },
    [componentProps, generateCode, code],
  )

  const updateProperty = useCallback((name: string, value: any) => {
    setComponentProps((prev) => ({
      ...prev,
      [name]: value,
    }))
  }, [])

  // VSCode-style token colors
  const getTokenStyle = useCallback((type: string): string => {
    const styles: Record<string, string> = {
      comment: "text-[#6A9955] italic",
      string: "text-[#CE9178]",
      keyword: "text-[#569CD6]",
      type: "text-[#4EC9B0]",
      number: "text-[#B5CEA8]",
      function: "text-[#DCDCAA]",
      property: "text-[#9CDCFE]",
      jsx: "text-[#4FC1FF]",
      jsxAttribute: "text-[#9CDCFE]",
      operator: "text-[#D4D4D4]",
      bracket: "text-[#D4D4D4]",
      variable: "text-[#9CDCFE]",
      default: "text-[#D4D4D4]",
    }
    return styles[type] || styles.default
  }, [])

  const tokenize = useCallback((line: string): Token[] => {
    const tokens: Token[] = []
    const tokenized = new Array(line.length).fill(false)

    const patterns = [
      { type: "comment", regex: /(\/\/.*$|\/\*[\s\S]*?\*\/)/g },
      { type: "string", regex: /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/g },
      { type: "jsx", regex: /(<\/?[A-Z][a-zA-Z0-9]*(?:\s[^>]*)?\/?>|<>|<\/>)/g },
      { type: "jsxAttribute", regex: /(\w+)(?==)/g },
      {
        type: "keyword",
        regex:
          /\b(const|let|var|function|return|if|else|for|while|import|export|from|default|interface|type|extends|implements|class|public|private|protected|static|async|await|try|catch|finally|throw|new|this|super|null|undefined|true|false|break|continue|switch|case|do)\b/g,
      },
      {
        type: "type",
        regex:
          /\b(string|number|boolean|object|any|void|never|unknown|React\.ReactNode|React\.FC|HTMLElement|Event|Promise|Array|Map|Set)\b/g,
      },
      { type: "number", regex: /\b\d+\.?\d*\b/g },
      { type: "function", regex: /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/g },
      { type: "property", regex: /\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g },
      { type: "variable", regex: /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g },
      { type: "operator", regex: /[+\-*/%=<>!&|?:]/g },
      { type: "bracket", regex: /[{}[\]()]/g },
    ]

    patterns.forEach(({ type, regex }) => {
      let match
      const globalRegex = new RegExp(regex.source, regex.flags.includes("g") ? regex.flags : regex.flags + "g")

      while ((match = globalRegex.exec(line)) !== null) {
        const start = match.index!
        const end = start + match[0].length

        let canTokenize = true
        for (let i = start; i < end; i++) {
          if (tokenized[i]) {
            canTokenize = false
            break
          }
        }

        if (canTokenize) {
          tokens.push({
            type,
            content: match[0],
            index: start,
          })

          for (let i = start; i < end; i++) {
            tokenized[i] = true
          }
        }
      }
    })

    let currentStart = 0
    for (let i = 0; i <= line.length; i++) {
      if (i === line.length || tokenized[i]) {
        if (i > currentStart) {
          const content = line.slice(currentStart, i)
          if (content) {
            tokens.push({
              type: "default",
              content,
              index: currentStart,
            })
          }
        }

        while (i < line.length && tokenized[i]) {
          i++
        }
        currentStart = i
      }
    }

    return tokens.sort((a, b) => a.index - b.index)
  }, [])

  const renderHighlightedLine = useCallback(
    (line: string, lineIndex: number) => {
      if (!line.trim()) {
        return <span key={`${lineIndex}-empty`}>&nbsp;</span>
      }

      const indentMatch = line.match(/^(\s*)/)
      const indentSpaces = indentMatch ? indentMatch[1] : ""
      const trimmedLine = line.slice(indentSpaces.length)

      const tokens = tokenize(trimmedLine)

      return (
        <span key={`line-${lineIndex}`}>
          {indentSpaces && <span className="text-transparent select-none">{indentSpaces.replace(/ /g, "\u00A0")}</span>}
          {tokens.map((token, tokenIndex) => (
            <span key={`${lineIndex}-${tokenIndex}`} className={getTokenStyle(token.type)}>
              {token.content}
            </span>
          ))}
        </span>
      )
    },
    [tokenize, getTokenStyle],
  )

  const codeWithLineNumbers = useCallback(
    (codeToDisplay?: string) => {
      const displayCode = codeToDisplay || (generateCode ? generateCode(componentProps) : code)

      if (!displayCode)
        return [
          <div key="empty" className="flex">
            <span className="text-right pr-4 select-none text-[#858585] text-xs w-[50px] flex-shrink-0">1</span>
            <span className="text-[#6A9955] italic">// No code provided</span>
          </div>,
        ]

      const lines = displayCode.split("\n")
      return lines.map((line, i) => {
        return (
          <div key={i} className="flex hover:bg-[#2A2D2E] transition-colors group">
            <span className="text-right pr-4 select-none text-[#858585] text-xs w-[50px] flex-shrink-0 py-0.5 group-hover:text-[#CCCCCC]">
              {i + 1}
            </span>
            <span className="text-[#D4D4D4] leading-[1.4] py-0.5 font-mono text-[13px] flex-1">
              {renderHighlightedLine(line, i)}
            </span>
          </div>
        )
      })
    },
    [componentProps, generateCode, code, renderHighlightedLine],
  )

  const renderPropertyControl = useCallback(
    (property: ComponentProperty) => {
      const value = componentProps[property.name]

      switch (property.type) {
        case "select":
          return (
            <div key={property.name} className="flex items-center justify-between gap-3">
              <Label className="text-sm font-medium min-w-[80px]">{property.label}</Label>
              <Select
                value={value || getDisplayValue(property.defaultValue)}
                onValueChange={(newValue) => updateProperty(property.name, newValue)}
              >
                <SelectTrigger className="w-full max-w-[180px] h-8">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {property.options?.map((option) => (
                    <SelectItem key={option} value={option}>
                      {option}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          )

        case "boolean":
          return (
            <div key={property.name} className="flex items-center justify-between gap-3">
              <Label className="text-sm font-medium min-w-[80px]">{property.label}</Label>
              <Switch
                checked={value ?? property.defaultValue}
                onCheckedChange={(checked) => updateProperty(property.name, checked)}
              />
            </div>
          )

        case "textarea":
          return (
            <div key={property.name} className="flex items-start justify-between gap-3">
              <Label className="text-sm font-medium min-w-[80px] pt-2">{property.label}</Label>
              <Textarea
                value={value ?? property.defaultValue}
                onChange={(e) => updateProperty(property.name, e.target.value)}
                className="w-full max-w-[180px] min-h-[60px]"
              />
            </div>
          )

        case "number":
          return (
            <div key={property.name} className="flex items-center justify-between gap-3">
              <Label className="text-sm font-medium min-w-[80px]">{property.label}</Label>
              <Input
                type="number"
                value={value ?? property.defaultValue}
                onChange={(e) => updateProperty(property.name, Number(e.target.value))}
                className="w-full max-w-[180px] h-8"
              />
            </div>
          )

        case "text":
        default:
          return (
            <div key={property.name} className="flex items-center justify-between gap-3">
              <Label className="text-sm font-medium min-w-[80px]">{property.label}</Label>
              <Input
                type="text"
                value={value ?? property.defaultValue}
                onChange={(e) => updateProperty(property.name, e.target.value)}
                className="w-full max-w-[180px] h-8"
              />
            </div>
          )
      }
    },
    [componentProps, updateProperty],
  )

  if (!mounted) {
    return (
      <div className={cn("w-full mb-12 opacity-0", className)}>
        <div className="h-[360px]"></div>
      </div>
    )
  }

  const hasProperties = properties.length > 0

  return (
    <div className={cn("w-full mb-12", className)}>
      {title && (
        <div className="mb-4" style={{ fontFamily: "var(--font-family)" }}>
          <h4 className="text-foreground text-lg font-medium">{title}</h4>
          {description && <p className="text-muted-foreground text-sm mt-1">{description}</p>}
        </div>
      )}

      <Tabs defaultValue={defaultTab} className="w-full">
        <div className="flex items-center justify-between mb-2">
          <TabsList
            className="inline-flex h-8 items-center justify-center rounded-md bg-[var(--background-secondary)] p-1 text-muted-foreground"
            style={{ fontFamily: "var(--font-family)" }}
          >
            <TabsTrigger
              value="preview"
              className="inline-flex items-center justify-center whitespace-nowrap text-xs px-2 py-1 h-6 rounded-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-[var(--background-primary)] data-[state=active]:text-foreground data-[state=active]:shadow-sm"
            >
              Preview
            </TabsTrigger>
            <TabsTrigger
              value="code"
              className="inline-flex items-center justify-center whitespace-nowrap text-xs px-2 py-1 h-6 rounded-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-[var(--background-primary)] data-[state=active]:text-foreground data-[state=active]:shadow-sm"
            >
              Code
            </TabsTrigger>
          </TabsList>

          {hasProperties && (
            <Button
              variant="outline"
              size="sm"
              onClick={() => setShowProperties(!showProperties)}
              className="flex items-center gap-2"
            >
              <Settings className="h-4 w-4" />
              Properties
              <ChevronDown className={cn("h-4 w-4 transition-transform", showProperties && "rotate-180")} />
            </Button>
          )}
        </div>

        <div className="border border-border rounded-md overflow-hidden">
          <TabsContent value="preview" className="m-0">
            <div className="flex">
              <div
                className="flex-1 p-16 flex items-center justify-center min-h-[200px] relative overflow-visible"
                style={{
                  fontFamily: "var(--font-family)",
                  backgroundColor: "hsl(var(--background-primary))",
                }}
              >
                <div className="relative z-10 overflow-visible">
                  {renderComponent ? renderComponent(componentProps) : children}
                </div>
              </div>

              {/* Properties Panel */}
              {hasProperties && showProperties && (
                <div className="w-80 border-l border-border bg-muted/30 p-6 space-y-6">
                  <div className="flex items-center justify-between">
                    <h3 className="font-semibold text-sm">Component Properties</h3>
                    <Badge variant="secondary" className="text-xs">
                      {Object.keys(componentProps).length} props
                    </Badge>
                  </div>

                  <div className="space-y-3">{properties.map(renderPropertyControl)}</div>

                  <div className="pt-4 border-t border-border">
                    <Button onClick={() => copyToClipboard()} size="sm" className="w-full flex items-center gap-2">
                      {copied ? (
                        <>
                          <Check className="h-4 w-4" />
                          Copied!
                        </>
                      ) : (
                        <>
                          <Copy className="h-4 w-4" />
                          Copy Current Variant
                        </>
                      )}
                    </Button>
                  </div>
                </div>
              )}
            </div>
          </TabsContent>

          <TabsContent value="code" className="m-0">
            <div className="bg-[#1E1E1E] text-[#D4D4D4] rounded-t-none font-mono">
              <div className="flex items-center justify-between px-4 py-2 border-b border-[#2D2D30]">
                <div className="text-xs text-[#CCCCCC]">
                  {(title || "component").toLowerCase().replace(/\s+/g, "-")}.{language}
                </div>
                <button
                  onClick={() => copyToClipboard()}
                  className="p-1 rounded hover:bg-[#404040] transition-colors group"
                  title="Copy code"
                >
                  {copied ? (
                    <Check className="h-4 w-4 text-[#28CA42]" />
                  ) : (
                    <Copy className="h-4 w-4 text-[#CCCCCC] group-hover:text-white" />
                  )}
                </button>
              </div>

              <div className="p-4 overflow-x-auto">
                <div className="space-y-0">{codeWithLineNumbers()}</div>
              </div>
            </div>
          </TabsContent>
        </div>
      </Tabs>
    </div>
  )
}
