import { forwardRef } from "react";
import { cn } from "@/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";

/**
 * Code Block component for displaying code snippets and inline code
 * 
 * @example
 * ```tsx
 * <CodeBlock>const greeting = "Hello, world!";</CodeBlock>
 * 
 * <CodeBlock variant="inline">const x = 10;</CodeBlock>
 * 
 * <CodeBlock language="python" showLineNumbers>
 *   def hello_world():
 *       print("Hello, world!")
 * </CodeBlock>
 * ```
 */

const codeBlockVariants = cva(
  "font-mono text-sm rounded-md",
  {
    variants: {
      variant: {
        default: "bg-muted text-foreground p-4 overflow-x-auto",
        inline: "bg-muted px-1.5 py-0.5 text-primary-foreground",
        terminal: "bg-black text-white p-4",
      },
      language: {
        none: "",
        js: "",
        ts: "",
        jsx: "",
        tsx: "",
        html: "",
        css: "",
        python: "",
        ruby: "",
        java: "",
        csharp: "",
        go: "",
        rust: "",
        php: "",
        swift: "",
        shell: "",
        sql: "",
        markdown: "",
        json: "",
        yaml: "",
      },
    },
    defaultVariants: {
      variant: "default",
      language: "none",
    },
  }
);

export interface CodeBlockProps
  extends React.HTMLAttributes<HTMLPreElement>,
    VariantProps<typeof codeBlockVariants> {
  /**
   * Whether to show line numbers
   */
  showLineNumbers?: boolean;
  /**
   * Whether this is a single line of code (uses inline styling)
   */
  inline?: boolean;
  /**
   * Optional title for the code block
   */
  title?: string;
}

const CodeBlock = forwardRef<HTMLPreElement, CodeBlockProps>(
  ({ 
    className, 
    variant = "default", 
    language, 
    showLineNumbers = false,
    inline = false,
    title,
    children,
    ...props 
  }, ref) => {
    // If inline is true, override variant to "inline"
    const actualVariant = inline ? "inline" : variant;
    
    // If inline, render as inline code element
    if (inline) {
      return (
        <code
          className={cn(codeBlockVariants({ variant: actualVariant, language, className }))}
          {...props}
        >
          {children}
        </code>
      );
    }

    // Process code content for line numbers if needed
    let codeContent = children;
    if (showLineNumbers && typeof children === 'string') {
      const lines = children.toString().trim().split('\n');
      const lineCount = lines.length;
      const lineNumberWidth = lineCount.toString().length;
      
      codeContent = (
        <div className="flex">
          <div className="flex-none pr-4 text-muted-foreground select-none border-r border-muted-foreground/20 mr-4">
            {lines.map((_, idx) => (
              <div key={idx} className="text-right">
                {(idx + 1).toString().padStart(lineNumberWidth, ' ')}
              </div>
            ))}
          </div>
          <div className="flex-1">
            {lines.map((line, idx) => (
              <div key={idx}>{line || ' '}</div>
            ))}
          </div>
        </div>
      );
    }

    return (
      <div className="relative my-6 rounded-md overflow-hidden">
        {title && (
          <div className="bg-muted-foreground/10 text-muted-foreground px-4 py-1.5 text-sm font-medium border-b border-border">
            {title}
          </div>
        )}
        <pre
          className={cn(
            codeBlockVariants({ variant: actualVariant, language, className }),
            showLineNumbers && "pl-0"
          )}
          ref={ref}
          {...props}
        >
          {language && (
            <div className="absolute right-2 top-2 bg-muted-foreground/20 text-muted-foreground px-2 py-0.5 rounded text-xs uppercase">
              {language}
            </div>
          )}
          {codeContent}
        </pre>
      </div>
    );
  }
);

CodeBlock.displayName = "CodeBlock";

export { CodeBlock, codeBlockVariants };