<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import { useEcho } from '@laravel/echo-vue';
import {
    Chart as ChartJS,
    Title,
    Tooltip,
    Legend,
    BarElement,
    CategoryScale,
    LinearScale,
    PointElement,
    LineElement,
} from 'chart.js';
import { computed, onMounted, ref, watch } from 'vue';
import LinkHeader from '@/components/LinkHeader.vue';
import type {
    Dataset,
    InitializationMethod,
    Iteration,
    PerceptronType,
} from '@/types/perceptron';
import IterationTable from '../components/IterationTable.vue';
import PerceptronDecisionGraph from '../components/PerceptronDecisionGraph.vue';
import PerceptronIterationsErrorsGraph from '../components/PerceptronIterationsErrorsGraph.vue';
import PerceptronSetup from '../components/PerceptronSetup.vue';

ChartJS.register(
    Title,
    Tooltip,
    Legend,
    BarElement,
    CategoryScale,
    LinearScale,
    PointElement,
    LineElement,
);
ChartJS.defaults.font.size = 16;
ChartJS.defaults.color = '#FFF';
ChartJS.defaults.backgroundColor = '#AAA';

const props = defineProps<{
    type: PerceptronType;
    sessionId: string;
    datasets: Dataset[];
    minError: number;
    learningRate: number;
    maxIterations: number;
}>();

const selectedDatasetName = ref<string>('');
const dataset = computed<number[][]>(() => {
    const selected = props.datasets.find(
        (d) => d.label === selectedDatasetName.value,
    );

    return selected ? selected.data : [];
});
const cleanedDataset = computed<
    {
        label: number;
        data: { x: number; y: number }[];
    }[]
>(() => {
    if (!dataset.value) {
        return [];
    }

    const cleanedDataset: {
        label: number;
        data: { x: number; y: number }[];
    }[] = [];
    // Separate data into each dataset based on value of the last column (label)
    dataset.value.forEach((row) => {
        const label = row[row.length - 1];
        const dataPoint = { x: row[0], y: row[1] };

        let dataset = cleanedDataset.find((d) => d.label === label);
        if (!dataset) {
            dataset = { label, data: [] };
            cleanedDataset.push(dataset);
        }
        dataset.data.push(dataPoint);
    });
    return cleanedDataset;
});
const initializationMethod = ref<InitializationMethod>('zeros');

console.log('Session ID:', props.sessionId);

useEcho(
    `${props.sessionId}-perceptron-training`,
    'PerceptronTrainingIteration',
    percpetronIteration,
    [{}],
    'public',
);
useEcho(
    `${props.sessionId}-perceptron-training`,
    'PerceptronTrainingEnded',
    perceptronTrainingEnded,
    [{}],
    'public',
);
useEcho(
    `${props.sessionId}-perceptron-training`,
    'PerceptronInitialization',
    perceptroninitialization,
    [{}],
    'public',
);

const iterations = ref<Iteration[]>([]);

const trainingId  = ref<string>('');
function percpetronIteration(data: any) {
    console.log('Received perceptron iteration data:', data);
    if (data.trainingId !== trainingId.value) {
        console.warn(
            `Received iteration for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this iteration.`
        );
        return;
    }
    iterations.value.push(...data.iterations);
}

const trainingEnded = ref(false);
const trainingEndReason = ref('');
function perceptronTrainingEnded(data: any) {
    console.log('Perceptron training ended:', data);
    if (data.trainingId !== trainingId.value) {
        console.warn(
            `Received training ended event for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this event.`
        );
        return;
    }
    trainingEnded.value = true;
    trainingEndReason.value = data.reason;
}

const activationFunction = ref<string>('');
function perceptroninitialization(data: any) {
    console.log('Perceptron training initialized:', data);
    if (data.trainingId !== trainingId.value) {
        console.warn(
            `Received initialization event for training ID ${data.trainingId}, but current training ID is ${trainingId.value}. Ignoring this event.`
        );
        return;
    }
    activationFunction.value = data.activation_function;
}
function getActivationFunction(type: string): (x: number) => number {
    switch (type) {
        case 'step':
            return (x) => (x >= 0 ? 1 : 0);
        case 'sigmoid':
            return (x) => 1 / (1 + Math.exp(-x));
        case 'tanh':
            return (x) => Math.tanh(x);
        default:
            return (x) => x; // Identity function as fallback
    }
}

function resetTraining() {
    iterations.value = [];
    trainingEnded.value = false;
    trainingEndReason.value = '';
    activationFunction.value = '';
}
</script>

<template>
    <Head title="Perceptron Viewer"></Head>
    <main class="space-y-6">
        <LinkHeader class="w-full" />
            <PerceptronSetup
                :type="props.type"
                :datasets="props.datasets"
                :selectedDataset="selectedDatasetName"
                :initializationMethod="initializationMethod"
                :minError="props.minError"
                :sessionId="props.sessionId"
                :defaultLearningRate="props.learningRate"
                :defaultMaxIterations="props.maxIterations"
                @update:selected-dataset="
                    (newValue) => {
                        selectedDatasetName = newValue;
                    }
                "
                @update:training-id="
                    (newValue) => {
                        trainingId = newValue;
                        resetTraining();
                    }"
            />
        <div
            class="align-items-start justify-content-center flex h-full min-h-dvh max-w-dvw"
            v-if="selectedDatasetName || iterations.length > 0"
        >
            <div class="max-h-full w-full overflow-y-scroll">
                <IterationTable
                    :iterations="iterations"
                    :trainingEnded="trainingEnded"
                    :trainingEndReason="trainingEndReason"
                />
            </div>
            <div class="sticky top-0 h-full w-full">
                <div>
                    <PerceptronDecisionGraph
                        :cleanedDataset="cleanedDataset"
                        :iterations="iterations"
                        :activation-function="
                            getActivationFunction(activationFunction)
                        "
                    />
                </div>
                <div>
                    <PerceptronIterationsErrorsGraph
                        :iterations="iterations"
                        v-if="iterations.length > 0"
                    />
                </div>
            </div>
        </div>
    </main>
</template>
