import { signal, computed } from "@preact/signals";
import { useEffect } from "preact/hooks";
import { trpc } from "../trpc.js";
import {
  Chart as ChartJS,
  LinearScale,
  CategoryScale,
  PointElement,
  Tooltip,
  Title,
} from "chart.js";
import { Scatter } from "react-chartjs-2";
import {
  Container,
  Grid,
  Typography,
  TextField,
  Select,
  MenuItem,
  InputLabel,
  FormControl,
  Paper,
} from "@mui/material";

ChartJS.register(LinearScale, CategoryScale, PointElement, Tooltip, Title);

const availableUnderlyings = signal([]);
const chosenUnderlying = signal(null);

const chosenDaysToFrontExpiration = signal(14);

const chosenDaysBetweenFrontAndBackExpiration = signal(14);

const chosenStrikePercentageFromUnderlyingPrice = signal(1.4);
const chosenStrikePercentageFromUnderlyingPriceRadius = signal(0.05);

const chosenExitToFrontExpiration = signal(2);

const historicalStockQuoteChartData = signal([]);

const historicalCalendarQuoteChartData = signal([]);

const historicalCalendarExitQuoteChartData = signal([]);

const chosenLookbackPeriodStart = signal("2022-01-01");
const chosenLookbackPeriodEnd = signal("2024-01-01");

const maxChartPrice = computed(() =>
  Math.max(
    Math.max.apply(
      null,
      historicalCalendarQuoteChartData.value.map((d) => d.y)
    ),
    Math.max.apply(
      null,
      historicalCalendarExitQuoteChartData.value.map((d) => d.y)
    )
  )
);

const maxN = computed(() =>
  Math.max.apply(
    null,
    historicalCalendarExitQuoteChartData.value.map((d) => d.n)
  )
);

const refreshHistoricalStockQuoteChartData = () => {
  historicalStockQuoteChartData.value = [];
  trpc.getHistoricalStockQuoteChartData
    .query({
      underlying: chosenUnderlying.value,
      lookbackPeriodStart: chosenLookbackPeriodStart.value,
      lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
    })
    .then((getHistoricalStockQuoteChartDataResponse) => {
      historicalStockQuoteChartData.value =
        getHistoricalStockQuoteChartDataResponse;
    });
};
const refreshHistoricalCalendarQuoteChartData = () => {
  historicalCalendarQuoteChartData.value = [];
  trpc.getHistoricalCalendarQuoteChartData
    .query({
      underlying: chosenUnderlying.value,
      daysToFrontExpiration: chosenDaysToFrontExpiration.value,
      daysBetweenFrontAndBackExpiration:
        chosenDaysBetweenFrontAndBackExpiration.value,
      strikePercentageFromUnderlyingPriceRangeMin:
        chosenStrikePercentageFromUnderlyingPrice.value -
        chosenStrikePercentageFromUnderlyingPriceRadius.value,
      strikePercentageFromUnderlyingPriceRangeMax:
        chosenStrikePercentageFromUnderlyingPrice.value +
        chosenStrikePercentageFromUnderlyingPriceRadius.value,
      lookbackPeriodStart: chosenLookbackPeriodStart.value,
      lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
    })
    .then((getHistoricalCalendarQuoteChartDataResponse) => {
      historicalCalendarQuoteChartData.value =
        getHistoricalCalendarQuoteChartDataResponse;
    });
};
const refreshHistoricalCalendarExitQuoteChartData = () => {
  historicalCalendarExitQuoteChartData.value = [];
  trpc.getHistoricalCalendarExitQuoteChartData
    .query({
      underlying: chosenUnderlying.value,
      daysToFrontExpiration: chosenExitToFrontExpiration.value,
      daysBetweenFrontAndBackExpiration:
        chosenDaysBetweenFrontAndBackExpiration.value,
      lookbackPeriodStart: chosenLookbackPeriodStart.value,
      lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
    })
    .then((getHistoricalCalendarExitQuoteChartDataResponse) => {
      historicalCalendarExitQuoteChartData.value =
        getHistoricalCalendarExitQuoteChartDataResponse;
    });
};
const handleInit = () => {
  trpc.getAvailableUnderlyings.query().then((availableUnderlyingsResponse) => {
    availableUnderlyings.value = availableUnderlyingsResponse;
    chosenUnderlying.value = availableUnderlyingsResponse[0];
    refreshHistoricalStockQuoteChartData();
    refreshHistoricalCalendarQuoteChartData();
    refreshHistoricalCalendarExitQuoteChartData();
  });
};
const handleUnderlyingChange = (e) => {
  if (chosenUnderlying.value !== e.target.value) {
    chosenUnderlying.value = e.target.value;
    refreshHistoricalStockQuoteChartData();
    refreshHistoricalCalendarQuoteChartData();
    refreshHistoricalCalendarExitQuoteChartData();
  }
};
const handleDaysToFrontExpirationChange = (e) => {
  if (chosenDaysToFrontExpiration.value !== parseInt(e.target.value)) {
    chosenDaysToFrontExpiration.value = parseInt(e.target.value);
    refreshHistoricalCalendarQuoteChartData();
  }
};
const handleDaysBetweenFrontAndBackExpirationChange = (e) => {
  if (
    chosenDaysBetweenFrontAndBackExpiration.value !== parseInt(e.target.value)
  ) {
    chosenDaysBetweenFrontAndBackExpiration.value = parseInt(e.target.value);
    refreshHistoricalCalendarQuoteChartData();
    refreshHistoricalCalendarExitQuoteChartData();
  }
};
const handleStrikePercentageFromUnderlyingPriceChange = (e) => {
  if (
    chosenStrikePercentageFromUnderlyingPrice.value !==
    parseFloat(e.target.value)
  ) {
    chosenStrikePercentageFromUnderlyingPrice.value = parseFloat(
      e.target.value
    );
    refreshHistoricalCalendarQuoteChartData();
  }
};
const handleStrikePercentageFromUnderlyingPriceRadiusChange = (e) => {
  if (
    chosenStrikePercentageFromUnderlyingPriceRadius.value !==
    parseFloat(e.target.value)
  ) {
    chosenStrikePercentageFromUnderlyingPriceRadius.value = parseFloat(
      e.target.value
    );
    refreshHistoricalCalendarQuoteChartData();
  }
};
const handleExitToFrontExpirationChange = (e) => {
  if (chosenExitToFrontExpiration.value !== parseInt(e.target.value)) {
    chosenExitToFrontExpiration.value = parseInt(e.target.value);
    refreshHistoricalCalendarExitQuoteChartData();
  }
};

const handleLookbackPeriodStartChange = (e) => {
  if (chosenLookbackPeriodStart.value !== e.target.value) {
    chosenLookbackPeriodStart.value = e.target.value;
    refreshHistoricalStockQuoteChartData();
    refreshHistoricalCalendarQuoteChartData();
    refreshHistoricalCalendarExitQuoteChartData();
  }
};
const handleLookbackPeriodEndChange = (e) => {
  if (chosenLookbackPeriodEnd.value !== e.target.value) {
    chosenLookbackPeriodEnd.value = e.target.value;
    refreshHistoricalStockQuoteChartData();
    refreshHistoricalCalendarQuoteChartData();
    refreshHistoricalCalendarExitQuoteChartData();
  }
};

export function HistoricalCalendarPrices() {
  useEffect(handleInit, []);

  return (
      <Container maxWidth="lg">
        <Grid container spacing={4}>
          <Grid item xs={12}>
            <Typography variant="h4" gutterBottom>
              Historical Calendar Prices
            </Typography>
          </Grid>
          <Grid item xs={12} md={6}>
            <Paper elevation={3} sx={{ p: 3 }}>
              <Grid container spacing={2}>
                <Grid item xs={12}>
                  <FormControl fullWidth>
                    <InputLabel>Available Underlyings</InputLabel>
                    <Select
                      value={chosenUnderlying.value || ""}
                      onChange={handleUnderlyingChange}
                      label="Available Underlyings"
                    >
                      {availableUnderlyings.value.map((underlying) => (
                        <MenuItem key={underlying} value={underlying}>
                          {underlying}
                        </MenuItem>
                      ))}
                    </Select>
                  </FormControl>
                </Grid>
                <Grid item xs={12}>
                  <TextField
                    fullWidth
                    label="Now-to-Front-Month Days to Expiration"
                    type="number"
                    value={chosenDaysToFrontExpiration.value}
                    onChange={handleDaysToFrontExpirationChange}
                    InputProps={{ endAdornment: "Days" }}
                  />
                </Grid>
                <Grid item xs={12}>
                  <TextField
                    fullWidth
                    label="Front-to-Back-Month Days to Expiration Difference"
                    type="number"
                    value={chosenDaysBetweenFrontAndBackExpiration.value}
                    onChange={handleDaysBetweenFrontAndBackExpirationChange}
                    InputProps={{ endAdornment: "Days Difference" }}
                  />
                </Grid>
                <Grid item xs={6}>
                  <TextField
                    fullWidth
                    label="Strike % From Underlying Price"
                    type="number"
                    value={chosenStrikePercentageFromUnderlyingPrice.value}
                    onChange={handleStrikePercentageFromUnderlyingPriceChange}
                    InputProps={{ endAdornment: "%" }}
                  />
                </Grid>
                <Grid item xs={6}>
                  <TextField
                    fullWidth
                    label="Strike % Radius"
                    type="number"
                    value={chosenStrikePercentageFromUnderlyingPriceRadius.value}
                    onChange={handleStrikePercentageFromUnderlyingPriceRadiusChange}
                    InputProps={{ endAdornment: "%" }}
                  />
                </Grid>
                <Grid item xs={12}>
                  <TextField
                    fullWidth
                    label="Exit-to-Front-Month Days to Expiration"
                    type="number"
                    value={chosenExitToFrontExpiration.value}
                    onChange={handleExitToFrontExpirationChange}
                    InputProps={{ endAdornment: "Days" }}
                  />
                </Grid>
                <Grid item xs={6}>
  <TextField
    fullWidth
    label="Lookback Period Start"
    type="date"
    value={chosenLookbackPeriodStart.value}
    onChange={(e) => handleLookbackPeriodStartChange({ target: { value: e.target.value } })}
    InputLabelProps={{ shrink: true }}
  />
</Grid>
<Grid item xs={6}>
  <TextField
    fullWidth
    label="Lookback Period End"
    type="date"
    value={chosenLookbackPeriodEnd.value}
    onChange={(e) => handleLookbackPeriodEndChange({ target: { value: e.target.value } })}
    InputLabelProps={{ shrink: true }}
  />
</Grid>
              </Grid>
            </Paper>
          </Grid>
          <Grid item xs={12} md={6}>
            <Paper elevation={3} sx={{ p: 3, height: '100%' }}>
              {chosenUnderlying.value !== null &&
              historicalStockQuoteChartData.value.length > 0 ? (
                <Scatter
                  data={{
                    datasets: [
                      {
                        label: "Stock Open Price",
                        data: historicalStockQuoteChartData.value,
                      },
                    ],
                  }}
                  options={{
                    scales: {
                      x: {
                        title: {
                          display: true,
                          text: "Time",
                        },
                        ticks: {
                          callback: function (value, index, ticks) {
                            return new Date((value as number) * 1000)
                              .toISOString()
                              .substring(0, 10);
                          },
                        },
                        min:
                          new Date(chosenLookbackPeriodStart.value).getTime() /
                          1000,
                        max:
                          new Date(chosenLookbackPeriodEnd.value).getTime() /
                          1000,
                      },
                      y: {
                        beginAtZero: false,
                        ticks: {
                          callback: function (value, index, ticks) {
                            return "$" + value.toString();
                          },
                        },
                      },
                    },
                    elements: {
                      point: {
                        radius: 1,
                        borderWidth: 0,
                      },
                    },
                    plugins: {
                      tooltip: {
                        enabled: false,
                      },
                      legend: {
                        display: false,
                      },
                      title: {
                        display: true,
                        text: "Stock Price",
                      },
                    },
                    animation: false,
                    maintainAspectRatio: false,
                    events: [],
                  }}
                />
              ) : (
                <Typography>Loading Chart...</Typography>
              )}
            </Paper>
          </Grid>
          <Grid item xs={12}>
            <Paper elevation={3} sx={{ p: 3 }}>
              {chosenUnderlying.value !== null &&
              historicalCalendarQuoteChartData.value.length > 0 ? (
                <Scatter
                  data={{
                    datasets: [
                      {
                        label: "Calendar Open Price",
                        data: historicalCalendarQuoteChartData.value,
                      },
                    ],
                  }}
                  options={{
                    scales: {
                      x: {
                        title: {
                          display: true,
                          text: "Time",
                        },
                        ticks: {
                          callback: function (value, index, ticks) {
                            return new Date((value as number) * 1000)
                              .toISOString()
                              .substring(0, 10);
                          },
                        },
                        min:
                          new Date(chosenLookbackPeriodStart.value).getTime() /
                          1000,
                        max:
                          new Date(chosenLookbackPeriodEnd.value).getTime() /
                          1000,
                      },
                      y: {
                        beginAtZero: true,
                        ticks: {
                          callback: function (value, index, ticks) {
                            return "$" + value.toString();
                          },
                        },
                        min: 0,
                        max: maxChartPrice.value,
                      },
                    },
                    plugins: {
                      tooltip: {
                        enabled: false,
                      },
                      legend: {
                        display: false,
                      },
                      title: {
                        display: true,
                        text: "Calendar Price (Under Like Conditions)",
                      },
                    },
                    animation: false,
                    maintainAspectRatio: false,
                    events: [],
                  }}
                />
              ) : (
                <Typography>Loading Chart...</Typography>
              )}
            </Paper>
          </Grid>
          <Grid item xs={12}>
            <Paper elevation={3} sx={{ p: 3 }}>
              {chosenUnderlying.value !== null &&
              historicalCalendarQuoteChartData.value.length > 0 ? (
                <Scatter
                  data={{
                    datasets: [
                      {
                        label: "Calendar Exit Price",
                        data: historicalCalendarExitQuoteChartData.value,
                      },
                    ],
                  }}
                  options={{
                    scales: {
                      x: {
                        type: "linear",
                        beginAtZero: false,
                        title: {
                          display: true,
                          text: "%-From-the-Money",
                        },
                        ticks: {
                          callback: function (value, index, ticks) {
                            return value.toString() + "%";
                          },
                        },
                      },
                      y: {
                        beginAtZero: true,
                        ticks: {
                          callback: function (value, index, ticks) {
                            return "$" + value.toString();
                          },
                        },
                        min: 0,
                        max: maxChartPrice.value,
                      },
                    },
                    elements: {
                      point: {
                        borderWidth: 0,
                        backgroundColor: function (context) {
                          const n = (
                            context.raw as { x: number; y: number; n: number }
                          ).n;
                          const alpha = n / maxN.value;
                          return `rgba(0, 0, 0, ${alpha})`;
                        },
                      },
                    },
                    plugins: {
                      tooltip: {
                        enabled: false,
                      },
                      legend: {
                        display: false,
                      },
                      title: {
                        display: true,
                        text: [
                          "Calendar Prices at Exit",
                          "by %-age from-the-money",
                        ],
                      },
                    },
                    animation: false,
                    maintainAspectRatio: false,
                    events: [],
                  }}
                />
              ) : (
                <Typography>Loading Chart...</Typography>
              )}
            </Paper>
          </Grid>
        </Grid>
      </Container>
  );
}
