import { addPropertyControls, ControlType } from "framer"
import { useEffect, useRef } from "react"

/**
 * UploadFluid — v15
 *
 * A circular fluid fill animation for upload/loading states.
 * The fill level is driven externally via the fillProgress prop.
 *
 * ─── HOW TO USE ──────────────────────────────────────────────
 *
 * 1. ADD TO YOUR PROJECT
 *    In Framer: Assets → Code → + → paste this file → Publish
 *    Drag the component onto your canvas.
 *
 * 2. CONNECT FILL PROGRESS
 *    fillProgress accepts a number from 0 (empty) to 1 (full).
 *    Connect it to your upload state using Framer's variable system
 *    or via code override:
 *
 *    // Example code override
 *    import { override } from "framer"
 *
 *    export function withUploadProgress(): any {
 *      return {
 *        fillProgress: uploadedBytes / totalBytes
 *      }
 *    }
 *
 * 3. TRIGGER FROM A FILE INPUT
 *    Wire up a file input to track upload progress and update
 *    a shared variable that feeds into fillProgress:
 *
 *    const [progress, setProgress] = useState(0)
 *
 *    xhr.upload.onprogress = (e) => {
 *      setProgress(e.loaded / e.total)  // → feeds fillProgress
 *    }
 *
 * 4. EDITABLE PROPERTIES (visible in Framer's right panel)
 *    - fillProgress   : 0–1, connect to upload state
 *    - fluidColor     : color of the fluid fill
 *    - waveColor      : color of the wave surface highlight
 *    - size           : diameter of the circle in px
 *    - showPercentage : toggle the % number on/off
 *    - % Font Size    : size of the percentage label
 *    - % Font Weight  : weight of the percentage label
 *    - % Font Family  : font family of the percentage label
 *    - % Color        : color of the percentage label
 *
 * ─────────────────────────────────────────────────────────────
 */

function colorToRgb(color) {
    try {
        const tmp = document.createElement("canvas")
        tmp.width = tmp.height = 1
        const ctx = tmp.getContext("2d")
        ctx.fillStyle = color
        ctx.fillRect(0, 0, 1, 1)
        const d = ctx.getImageData(0, 0, 1, 1).data
        return [d[0], d[1], d[2]]
    } catch { return [79, 70, 229] }
}

export default function UploadFluid({
    fillProgress,
    fluidColor,
    waveColor,
    size,
    showPercentage,
    percentageFontSize,
    percentageFontWeight,
    percentageFontFamily,
    percentageColor,
}) {
    const canvasRef   = useRef(null)
    const frameRef    = useRef(null)
    const waveOffRef  = useRef(0)
    const lastTimeRef = useRef(null)

    useEffect(() => {
        const canvas = canvasRef.current
        if (!canvas) return

        canvas.width  = size
        canvas.height = size

        // Bowl is the bottom 3/4 of a circle
        // Open at the top — clipped from the top-left rim to top-right rim
        // via the bottom arc only

        const loop = (ts) => {
            if (lastTimeRef.current !== null) {
                const delta = (ts - lastTimeRef.current) / 1000
                waveOffRef.current += delta * 60
            }
            lastTimeRef.current = ts

            const ctx  = canvas.getContext("2d")
            const W    = size
            const H    = size
            const cx   = W / 2
            const cy   = H / 2
            const R    = W / 2 - 2

            ctx.clearRect(0, 0, W, H)

            // Full circle clip path
            const circlePath = () => {
                ctx.beginPath()
                ctx.arc(cx, cy, R, 0, Math.PI * 2)
                ctx.closePath()
            }

            const fill    = Math.max(0, Math.min(1, fillProgress))
            const waveOff = waveOffRef.current

            if (fill > 0) {
                ctx.save()
                circlePath()
                ctx.clip()

                // Fluid top Y — bottom of circle to top
                const bowlBottom = cy + R
                const bowlTopY   = cy - R
                const fluidTopY  = bowlBottom - fill * (bowlBottom - bowlTopY)

                const waveAmp  = fill >= 0.99 ? 8 : 5 * Math.sin(fill * Math.PI)
                const waveFreq = (2 * Math.PI) / (W * 0.55)

                const wavePath = (c) => {
                    c.moveTo(0, fluidTopY)
                    for (let x = 0; x <= W; x++) {
                        const y = fluidTopY
                            + Math.sin((x + waveOff) * waveFreq) * waveAmp
                            + Math.sin((x + waveOff * 0.6) * waveFreq * 1.7) * (waveAmp * 0.35)
                        c.lineTo(x, y)
                    }
                }

                // Fluid body
                ctx.beginPath()
                wavePath(ctx)
                ctx.lineTo(W, H)
                ctx.lineTo(0, H)
                ctx.closePath()
                ctx.fillStyle = fluidColor
                ctx.fill()

                // Inner shine
                const [fr, fg, fb] = colorToRgb(fluidColor)
                const grad = ctx.createLinearGradient(0, fluidTopY, 0, bowlBottom)
                grad.addColorStop(0, `rgba(${Math.min(fr+60,255)},${Math.min(fg+60,255)},${Math.min(fb+60,255)},0.22)`)
                grad.addColorStop(0.5, `rgba(${fr},${fg},${fb},0)`)
                ctx.beginPath()
                wavePath(ctx)
                ctx.lineTo(W, H)
                ctx.lineTo(0, H)
                ctx.closePath()
                ctx.fillStyle = grad
                ctx.fill()

                // Wave highlight on surface
                if (fill < 0.99) {
                    ctx.beginPath()
                    wavePath(ctx)
                    ctx.strokeStyle = waveColor
                    ctx.lineWidth   = 2
                    ctx.globalAlpha = 0.5
                    ctx.stroke()
                    ctx.globalAlpha = 1
                }

                ctx.restore()
            }


            frameRef.current = requestAnimationFrame(loop)
        }

        frameRef.current = requestAnimationFrame(loop)
        return () => cancelAnimationFrame(frameRef.current)
    }, [fluidColor, waveColor, size, fillProgress])

    const pct = Math.round(Math.max(0, Math.min(1, fillProgress)) * 100)

    return (
        <div style={{ display:"flex", alignItems:"center", justifyContent:"center", width:"100%", height:"100%" }}>
            <div style={{ position:"relative", display:"inline-block" }}>
                <canvas ref={canvasRef} style={{ display:"block" }} />
                {showPercentage && (
                    <div style={{
                        position: "absolute",
                        top: "50%",
                        left: "50%",
                        transform: "translate(-50%, -50%)",
                        fontFamily: percentageFontFamily,
                        fontSize: `${percentageFontSize}px`,
                        fontWeight: percentageFontWeight,
                        color: percentageColor,
                        lineHeight: 1,
                        pointerEvents: "none",
                        whiteSpace: "nowrap",
                        textAlign: "center",
                    }}>
                        {pct}%
                    </div>
                )}
            </div>
        </div>
    )
}

UploadFluid.defaultProps = {
    fillProgress:          0,
    fluidColor:            "#4f46e5",
    waveColor:             "#a5b4fc",
    size:                  160,
    showPercentage:        true,
    percentageFontSize:    15,
    percentageFontWeight:  "700",
    percentageFontFamily:  "Inter, sans-serif",
    percentageColor:       "#ffffff",
}

addPropertyControls(UploadFluid, {
    fillProgress: {
        type: ControlType.Number,
        title: "Fill Progress",
        defaultValue: 0,
        min: 0,
        max: 1,
        step: 0.01,
    },
    fluidColor: {
        type: ControlType.Color,
        title: "Fluid Color",
        defaultValue: "#4f46e5",
    },
    waveColor: {
        type: ControlType.Color,
        title: "Wave Highlight",
        defaultValue: "#a5b4fc",
    },
    size: {
        type: ControlType.Number,
        title: "Size (px)",
        defaultValue: 90,
        min: 60,
        max: 600,
        step: 10,
        displayStepper: true,
    },
    showPercentage: {
        type: ControlType.Boolean,
        title: "Show %",
        defaultValue: true,
        enabledTitle: "Yes",
        disabledTitle: "No",
    },
    percentageFontSize: {
        type: ControlType.Number,
        title: "% Font Size",
        defaultValue: 12,
        min: 8,
        max: 120,
        step: 1,
        displayStepper: true,
    },
    percentageFontWeight: {
        type: ControlType.Enum,
        title: "% Font Weight",
        defaultValue: "700",
        options: ["100","200","300","400","500","600","700","800","900"],
        optionTitles: ["Thin","Extra Light","Light","Regular","Medium","Semi Bold","Bold","Extra Bold","Black"],
    },
    percentageFontFamily: {
        type: ControlType.String,
        title: "% Font Family",
        defaultValue: "Inter, sans-serif",
    },
    percentageColor: {
        type: ControlType.Color,
        title: "% Color",
        defaultValue: "#ffffff",
    },
})
