/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

//@ts-nocheck
/* eslint-disable react-hooks/exhaustive-deps */
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import GaugeChart from "react-gauge-chart";
import { Progress } from "@/components/ui/progress";
import { Database, Info, InfoIcon, RefreshCcw, RefreshCw } from "lucide-react";
import { useContext, useEffect, useState } from "react";
import { middlewareApi } from "@/lib/api";
import { Loader } from "@/components/ui/loader";
import { Button } from "@/components/ui/button";
import { Link } from "react-router-dom";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { NotFound } from "@/components/ui/not-found";
import { useToast } from "@/hooks/use-toast";
import { useMode } from "@/contexts/ModeContext";

interface LevelDBStat {
  Level: string;
  Files: string;
  "Size(MB)": string;
  "Time(sec)": string;
  "Read(MB)": string;
  "Write(MB)": string;
}

interface StorageMetrics {
  ext_cache_hit_ratio: number;
  level_db_approx_mem_size: number;
  level_db_stats: LevelDBStat[];
  max_resident_set_size: number;
  resident_set_size: number;
  num_reads: number;
  num_writes: number;
}

interface MemoryMetric {
  name: string;
  value: string | number;
  description: string;
  link: string;
}

interface CacheHitRatioProps {
  ratio: number;
}

interface LevelDbCardProps {
  levelDbSize: number;
  rssSize: number;
  numReads: number;
  numWrites: number;
}

interface LevelDBStatsTableProps {
  stats: LevelDBStat[];
}
const CacheHitGauge = () => {
  const { api, refreshTrigger } = useMode();
  const [isCalculating, setIsCalculating] = useState(false);
  const [p99Value, setP99Value] = useState(0);
  const [animatedValue, setAnimatedValue] = useState(0);

  const calculateP99 = async () => {
    setIsCalculating(true);
    setP99Value(0);
    setAnimatedValue(0);

    try {
      const response = await api.post("/transactions/calculateP99", {
        samples: 100,
      });
      const data = response?.data;
      const finalValue = data.p99;
      setP99Value(finalValue);
      setIsCalculating(false);
    } catch (error) {
      console.error("Error calculating P99:", error);
      setIsCalculating(false);
    }
  };

  function calculatPercent() {
    return p99Value / 5000;
  }

  return (
    <Card className="flex-1">
      <CardHeader>
        <CardTitle>P99 Latency Test (Set Method)</CardTitle>
      </CardHeader>
      <CardContent className="p-6 flex flex-col items-center justify-center">
        {!isCalculating && p99Value === 0 ? (
          <Button
            onClick={calculateP99}
            className="w-32 h-32 rounded-full text-2xl font-bold"
            disabled={isCalculating}
          >
            GO
          </Button>
        ) : (
          <div className="w-full h-48 relative">
            <GaugeChart
              style={{ height: "12rem" }}
              id="p99-gauge-chart"
              nrOfLevels={10}
              colors={["#10B981", "#FBBF24", "#EF4444"]}
              percent={calculatPercent()}
              textColor="#000000"
              needleColor="#5C6BC0"
              needleBaseColor="#3949AB"
              arcWidth={0.2}
              formatTextValue={() => ""}
            />
            <div className="absolute inset-0 flex items-center justify-center">
              <div className="text-xl font-bold">
                {isCalculating
                  ? `${animatedValue.toFixed(1)}s`
                  : `${p99Value.toFixed(1)}ms`}
              </div>
            </div>
          </div>
        )}
        {isCalculating && (
          <p className="mt-1 text-center text-muted-foreground">
            Calculating P99 latency...
          </p>
        )}
        {!isCalculating && p99Value > 0 && (
          <Button onClick={calculateP99} className="mt-1">
            Recalculate
          </Button>
        )}
      </CardContent>
    </Card>
  );
};

export function StorageEngineMetrics() {
  const { toast } = useToast();
  const { mode, api, refreshTrigger } = useMode();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [refresh, setRefresh] = useState(false);
  const [data, setData] = useState<StorageMetrics>(null);

  useEffect(() => {
    fetchTransactionData();
  }, [refresh, refreshTrigger]);

  async function fetchTransactionData() {
    try {
      setLoading(true);
      const response = await api.post(
        "/statsExporter/getTransactionData"
      );
      setData(response?.data);
      toast({
        title: "Data Updated",
        description: "Storage Engine Metrics Fetched Successfully",
      });
      setLoading(false);
    } catch (error) {
      setLoading(false);
      setError(error);
    }
  }

  return (
    <Card className="flex-1 w-full max-w-8xl mx-auto bg-gradient-to-br from-slate-900 to-slate-950 text-white shadow-xl">
      <CardHeader className="flex flex-row items-center justify-between pb-2">
        <div className="flex items-center gap-2">
          <Database className="w-6 h-6 text-blue-400" />
          <CardTitle className="text-2xl font-bold">
            {" "}
            Storage Engine Metrics
          </CardTitle>
        </div>
        <div className="flex items-center gap-2">
          <Button
            variant="outline"
            size="icon"
            onClick={() => setRefresh((prev) => !prev)}
          >
            <RefreshCcw />
          </Button>
          <TooltipProvider>
            <Tooltip>
              <TooltipTrigger asChild>
                <button
                  className="p-2 bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors duration-200 ease-in-out rounded"
                >
                  <Info size={18.5} />
                </button>
              </TooltipTrigger>
              <TooltipContent>
                <p>Click for more information about these metrics</p>
              </TooltipContent>
            </Tooltip>
          </TooltipProvider>
        </div>
      </CardHeader>
      {loading ? (
        <Loader className="h-[400px]" />
      ) : (
        <CardContent className="space-y-4">
          <div className="flex flex-row justify-between space-x-2">
            <CacheHitRatio ratio={data?.ext_cache_hit_ratio} />
            <LevelDBSizeCard size={data?.level_db_approx_mem_size} />
            <LevelDbCard
              levelDbSize={data?.level_db_approx_mem_size}
              rssSize={data?.resident_set_size || 0}
              numReads={data?.num_reads}
              numWrites={data?.num_writes}
            />
            <CacheHitGauge />
          </div>
          <div className="flex flex-row justify-between space-x-2">
            {/* <LevelDBStatsTable stats={data?.level_db_stats} /> */}
          </div>
        </CardContent>
      )}
    </Card>
  );
}

export function CacheHitRatio({ ratio }: CacheHitRatioProps) {
  const percentage = Math.round(ratio * 100);
  return (
    <Card className="w-full max-w-md flex-1">
      <CardHeader>
        <CardTitle>Cache Hit Ratio</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="flex items-center justify-between mb-2">
          <span className="text-sm font-medium">Hit Rate</span>
          <span className="text-2xl font-bold">{percentage || 0}%</span>
        </div>
        <Progress value={percentage || 0} className="h-2" />
        <p className="mt-2 text-sm text-muted-foreground">
          {percentage || 0}% of requests are served from the LRU cache.
        </p>
      </CardContent>
    </Card>
  );
}

export function LevelDBStatsTable({ stats }: LevelDBStatsTableProps) {
  if (!stats) {
    return (
      <Card>
        <NotFound
          onRefresh={function (): void {
            throw new Error("Function not implemented.");
          }}
        />
      </Card>
    );
  }
  return (
    <Card className="w-full max-w-md flex-1">
      <CardHeader>
        <CardTitle>Level DB Stats</CardTitle>
      </CardHeader>
      <CardContent>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Level</TableHead>
              <TableHead>Files</TableHead>
              <TableHead>Size (MB)</TableHead>
              <TableHead>Time (sec)</TableHead>
              <TableHead>Read (MB)</TableHead>
              <TableHead>Write (MB)</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {stats.map((stat) => (
              <TableRow key={stat.Level}>
                <TableCell>{stat.Level}</TableCell>
                <TableCell>{stat.Files}</TableCell>
                <TableCell>{stat["Size(MB)"]}</TableCell>
                <TableCell>{stat["Time(sec)"]}</TableCell>
                <TableCell>{stat["Read(MB)"]}</TableCell>
                <TableCell>{stat["Write(MB)"]}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </CardContent>
    </Card>
  );
}

//TODO: refactor
export function LevelDbCard({
  levelDbSize,
  rssSize,
  numReads,
  numWrites,
}: LevelDbCardProps) {
  const size = Math.round(levelDbSize / 1000);

  const memoryMetrics: MemoryMetric[] = [
    // {
    //   name: "Level DB Approx Size",
    //   value: String(size) + " KB",
    //   description: "Estimated size of the LevelDB database",
    //   link: "https://github.com/google/leveldb",
    // },
    {
      name: "RSS",
      value: rssSize ? String(rssSize || 0) + " MB" : 0,
      description: "Current Resident Set Size (physical memory used)",
      link: "https://en.wikipedia.org/wiki/Resident_set_size",
    },
    {
      name: "Number of Reads by process",
      value: numReads,
      description:
        "Number of times the file system had to read from the disk on behalf of processes.",
      link: "https://www.gnu.org/software/libc/manual/html_node/Resource-Usage.html",
    },
    {
      name: "Number of Writes by process",
      value: numWrites,
      description:
        "The number of times the file system had to write to the disk on behalf of processes.",
      link: "https://www.gnu.org/software/libc/manual/html_node/Resource-Usage.html",
    },
  ];

  return (
    <Card className="w-full max-w-2xl">
      <CardHeader>
        <CardTitle>Memory Footprint</CardTitle>
      </CardHeader>
      <CardContent>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Metric</TableHead>
              <TableHead>Value</TableHead>
              <TableHead>Info</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {memoryMetrics.map((metric) => (
              <TableRow key={metric.name}>
                <TableCell>{metric.name}</TableCell>
                <TableCell>{metric.value || 0}</TableCell>
                <TableCell>
                  <TooltipProvider>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Link
                          to={metric.link}
                          target="_blank"
                          rel="noopener noreferrer"
                        >
                          <InfoIcon className="h-4 w-4 text-muted-foreground hover:text-foreground" />
                        </Link>
                      </TooltipTrigger>
                      <TooltipContent>
                        <p>{metric.description}</p>
                      </TooltipContent>
                    </Tooltip>
                  </TooltipProvider>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </CardContent>
    </Card>
  );
}

interface LevelDBSizeCardProps {
  size: number; // Size of the database, e.g., "256 MB"
}

export function LevelDBSizeCard({ size }: LevelDBSizeCardProps) {
  return (
    <Card className="w-full max-w-xs">
      <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
        <CardTitle className="text-sm font-medium">Database Size</CardTitle>
        <Database className="h-4 w-4 text-muted-foreground" />
      </CardHeader>
      <div className="flex flex-col justify-center items-center flex-grow p-6">
        <div className="text-3xl sm:text-4xl md:text-5xl font-bold text-center">
          {Math.floor((size || 0) / 1000)} KB
        </div>
        <p className="text-xs text-muted-foreground mt-2">LevelDB Storage</p>
        <p className="text-sm text-center mt-4 max-w-xs text-muted-foreground">
          Size of data present in LevelDB with compaction in place
        </p>
      </div>
    </Card>
  );
}

interface LevelDBStatsProps {
  totalSize: string;
  stats: LevelDBStat[];
  className?: string;
}

export function LevelDBStats({
  totalSize,
  stats,
  className,
}: LevelDBStatsProps) {
  const totalFiles = stats.reduce((sum, stat) => sum + stat.Files, 0);
  const totalSizeMB = stats.reduce((sum, stat) => sum + stat["Size(MB)"], 0);

  return (
    <div className={`space-y-4 ${className}`}>
      <Card className="w-full">
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-2xl font-bold">
            LevelDB Statistics
          </CardTitle>
          <Database className="h-6 w-6 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            <StatsCard
              title="Total Size"
              value={totalSize}
              description="Overall database size"
            />
            <StatsCard
              title="Total Files"
              value={totalFiles.toString()}
              description="Number of SSTable files"
            />
            <StatsCard
              title="Total Size (MB)"
              value={`${totalSizeMB.toFixed(2)} MB`}
              description="Sum of all level sizes"
            />
          </div>
        </CardContent>
      </Card>

      <Card className="w-full">
        <CardHeader>
          <CardTitle>Level DB Stats</CardTitle>
        </CardHeader>
        <CardContent>
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Level</TableHead>
                <TableHead>Files</TableHead>
                <TableHead>Size (MB)</TableHead>
                <TableHead>Time (sec)</TableHead>
                <TableHead>Read (MB)</TableHead>
                <TableHead>Write (MB)</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {stats.map((stat) => (
                <TableRow>
                  <TableCell>{stat.Level}</TableCell>
                  <TableCell>{stat.Files}</TableCell>
                  <TableCell>{stat["Size(MB)"]}</TableCell>
                  <TableCell>{stat["Time(sec)"]}</TableCell>
                  <TableCell>{stat["Read(MB)"]}</TableCell>
                  <TableCell>{stat["Write(MB)"]}</TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </CardContent>
      </Card>
    </div>
  );
}

function StatsCard({
  title,
  value,
  description,
}: {
  title: string;
  value: string;
  description: string;
}) {
  return (
    <Card>
      <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
        <CardTitle className="text-sm font-medium">{title}</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="text-2xl font-bold">{value}</div>
        <p className="text-xs text-muted-foreground">{description}</p>
      </CardContent>
    </Card>
  );
}
