"use client";
import {
Badge,
Box,
Button,
Card,
Flex,
Grid,
Heading,
HStack,
Icon,
IconButton,
Separator,
Text,
VStack,
} from "@chakra-ui/react";
import { useTranslations } from "next-intl";
import React from "react";
import {
LuBadgeAlert,
LuChartBar,
LuCircleHelp,
LuDatabase,
LuTrendingUp,
LuZap,
} from "react-icons/lu";
import { useColorModeValue } from "@/components/ui/color-mode";
import { Tooltip } from "@/components/ui/overlays/tooltip";
import { useGenerateFrequencyCoupon } from "@/lib/api/coupons/use-hooks";
import type {
FrequencyCouponResultDto,
FrequencyCouponBetDto,
} from "@/lib/api/coupons/types";
import { ApiError } from "@/lib/api/create-api-client";
import { useCouponStore } from "@/lib/stores/coupon-store";
const AVAILABLE_MARKETS = ["OU1.5", "OU2.5", "OU3.5", "BTTS", "MS"];
function InfoIcon({ content, label }: { content: string; label: string }) {
return (
);
}
const profileColor = (p: string) =>
({ GOLCU: "red", DEFANSIF: "blue", NORMAL: "gray" })[p] || "gray";
const profileLabel = (p: string, t: ReturnType) =>
({
GOLCU: t("freq-league-golcu"),
DEFANSIF: t("freq-league-defansif"),
NORMAL: t("freq-league-normal"),
})[p] || p;
export default function FrequencyPanel() {
const t = useTranslations("coupons");
const { addItem, clearCoupon } = useCouponStore();
const cardBg = useColorModeValue("white", "gray.800");
const mutedBg = useColorModeValue("gray.50", "whiteAlpha.50");
const borderColor = useColorModeValue("gray.200", "gray.700");
const freqMutation = useGenerateFrequencyCoupon();
const [minSignal, setMinSignal] = React.useState(0.65);
const [maxMatches, setMaxMatches] = React.useState(3);
const [selectedMarkets, setSelectedMarkets] = React.useState([]);
const [result, setResult] = React.useState<
FrequencyCouponResultDto | undefined
>(undefined);
const toggleMarket = (m: string) =>
setSelectedMarkets((prev) =>
prev.includes(m) ? prev.filter((x) => x !== m) : [...prev, m],
);
const handleGenerate = () => {
freqMutation.mutate(
{
maxMatches,
minSignal,
markets: selectedMarkets.length > 0 ? selectedMarkets : undefined,
},
{
onSuccess: (response) => {
const data = (response as any)?.data ?? response;
setResult(data as FrequencyCouponResultDto);
// Sync to coupon store
if (data && Array.isArray((data as any).bets)) {
clearCoupon();
(data as FrequencyCouponResultDto).bets.forEach(
(bet: FrequencyCouponBetDto) =>
addItem({
matchId: bet.match_id,
matchName: bet.match_name,
market: bet.market,
pick: bet.pick,
odd: bet.odds,
}),
);
}
},
onError: () => setResult(undefined),
},
);
};
const errorMessage =
freqMutation.error instanceof ApiError
? freqMutation.error.message
: freqMutation.error instanceof Error
? freqMutation.error.message
: undefined;
return (
{/* Controls Card */}
{t("freq-engine-title")}
{t("freq-engine-subtitle")}
{/* Min Signal Slider */}
{t("freq-min-signal")}
{(minSignal * 100).toFixed(0)}%
setMinSignal(Number(e.target.value) / 100)}
style={{
width: "100%",
accentColor: "#0891b2",
cursor: "pointer",
}}
/>
50%
95%
{/* Max Matches */}
{t("match-count-label")}
{maxMatches}
setMaxMatches(Number(e.target.value))}
style={{
width: "100%",
accentColor: "#9333ea",
cursor: "pointer",
}}
/>
2
5
{/* Market Filter */}
{t("freq-markets")}
{AVAILABLE_MARKETS.map((m) => {
const active = selectedMarkets.includes(m);
return (
toggleMarket(m)}
_hover={{ opacity: 0.8 }}
>
{m}
);
})}
{selectedMarkets.length === 0 && (
Tüm marketler taranacak
)}
{/* Results Card */}
{result && result.bets.length > 0 && (
{t("freq-engine-title")}
{result.ev_positive
? t("freq-ev-positive")
: t("freq-ev-negative")}
{/* EV Stats */}
{t("freq-ev-label")}
{result.expected_value.toFixed(3)}
{t("freq-hit-rate")}
{(result.expected_hit_rate * 100).toFixed(1)}%
{t("total-odds")}
{result.total_odds.toFixed(2)}
{/* Bets */}
{result.bets.map((bet: FrequencyCouponBetDto) => (
{bet.match_name}
{bet.league} • {bet.market}: {bet.pick}
{bet.odds.toFixed(2)}
{t("freq-home-signal")}
{(bet.home_signal * 100).toFixed(0)}%
{bet.home_odds_band}
{t("freq-away-signal")}
{(bet.away_signal * 100).toFixed(0)}%
{bet.away_odds_band}
{t("freq-combined-signal")}
{(bet.combined_signal * 100).toFixed(0)}%
{t("freq-league-profile")}:{" "}
{profileLabel(bet.league_profile, t)}
{t("freq-match-count")}: {bet.home_match_count}/
{bet.away_match_count}
))}
{/* Reasoning */}
{result.reasoning.length > 0 && (
{t("freq-reasoning-title")}
{result.reasoning.map((r, i) => (
• {r}
))}
)}
{/* Rejected */}
{result.rejected_matches.length > 0 && (
{t("rejected-matches-title")}
{result.rejected_matches.map((entry, i) => (
{entry.match_name}: {entry.reason}
))}
)}
)}
{/* No result message */}
{result && result.bets.length === 0 && (
{t("freq-no-result")}
)}
{/* Error */}
{errorMessage && (
{errorMessage}
)}
);
}