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 './style.css';

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 refreshHistoricalStockQuoteChartData = ()=>{
  trpc.getHistoricalStockQuoteChartData
    .query({
      underlying:chosenUnderlying.value,
      lookbackPeriodStart:chosenLookbackPeriodStart.value,
      lookbackPeriodEnd:chosenLookbackPeriodEnd.value,
    })
    .then((getHistoricalStockQuoteChartDataResponse)=>{
      historicalStockQuoteChartData.value = getHistoricalStockQuoteChartDataResponse;
    })
};
const refreshHistoricalCalendarQuoteChartData = ()=>{
  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 = ()=>{
  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 (
    <div>
      <div>
        <label>Available Underlyings</label>
        {
          availableUnderlyings.value.length === 0 
          ? "Loading..." 
          : <select onChange={handleUnderlyingChange}>
              {availableUnderlyings.value.map((availableUnderlying)=>(
                <option value={availableUnderlying}>{availableUnderlying}</option>
              ))}
            </select>
        }
      </div>
      <div>
        <label>Now-to-Front-Month "Days to Expiration"</label>
        <input type="text" onBlur={handleDaysToFrontExpirationChange} value={chosenDaysToFrontExpiration.value} />
        Days
      </div>
      <div>
        <label>Front-to-Back-Month "Days to Expiration" Difference</label>
        <input type="text" onBlur={handleDaysBetweenFrontAndBackExpirationChange} value={chosenDaysBetweenFrontAndBackExpiration.value} />
        Days Difference
      </div>
      <div>
        <label>"Strike Percentage From Underlying Price" Range</label>
        <input type="text" onBlur={handleStrikePercentageFromUnderlyingPriceChange} value={chosenStrikePercentageFromUnderlyingPrice.value} />
        %
        +/-
        <input type="text" onBlur={handleStrikePercentageFromUnderlyingPriceRadiusChange} value={chosenStrikePercentageFromUnderlyingPriceRadius.value} />
        % from ATM
      </div>
      <div>
        <label>Exit-to-Front-Month "Days to Expiration"</label>
        <input type="text" onBlur={handleExitToFrontExpirationChange} value={chosenExitToFrontExpiration.value} />
        Days
      </div>
      <div>
        <label>Lookback Period</label>
        <input type="text" onBlur={handleLookbackPeriodStartChange} value={chosenLookbackPeriodStart.value} />
        -
        <input type="text" onBlur={handleLookbackPeriodEndChange} value={chosenLookbackPeriodEnd.value} />
      </div>
      <div className="chart-container">
        {chosenUnderlying.value!==null && historicalStockQuoteChartData.value.length>0
        ? <div className="chart">
            <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,
              }}
            />
          </div>
        : <div>Loading Chart...</div>}
      </div>
      <div className="chart-container">
        {chosenUnderlying.value!==null && historicalCalendarQuoteChartData.value.length>0
        ? <div className="chart">
            <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,
              }}
            />
          </div>
        : <div>Loading Chart...</div>}

        {chosenUnderlying.value!==null && historicalCalendarQuoteChartData.value.length>0
        ? <div className="chart">
            <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,
                  },
                },
                plugins: {
                  tooltip: {
                    enabled: false,
                  },
                  legend: {
                    display: false,
                  },
                  title: {
                    display: true,
                    text: ["Calendar Prices at Exit","by %-age from-the-money"]
                  },
                },
                animation: false,
                maintainAspectRatio: false,
              }}
            />
          </div>
        : <div>Loading Chart...</div>}
      </div>
    </div>
  );
}