import { PanelOptions, TaskTableRowConfig, QueryTableRowConfig, DatasourceType } from '../types';

import { convertTimestampToDate, getDashboardUid } from '../../../utils';
import { CLOSE_ICON_BASE_64, DOWNLOAD_ICON_BASE_64, SELECT_ICON_BASE_64, UNSELECT_ICON_BASE_64 } from '../../../icons';

import { queryApi } from '../../../services/api_service';
import { getDashboardByUid, getDatasources } from '../../../services/grafana_backend_service';

import { contextSrv } from 'grafana/app/core/core';

import { Table, Button, HorizontalGroup, Modal, LoadingPlaceholder } from '@grafana/ui';
import {
  PanelProps,
  toDataFrame,
  FieldType,
  applyFieldOverrides,
  createTheme,
  DataFrame,
  DataLinkClickEvent,
  PanelModel,
  DataQuery,
  DataSourceSettings,
} from '@grafana/data';

import React, { useState, useEffect } from 'react';
import * as _ from 'lodash';

interface Props extends PanelProps<PanelOptions> {}

export function Panel({ width, height, timeRange }: Props) {

  // TODO: Dashboard type
  const [dashboard, setDashboard] = useState<any | null>(null);
  const [datasources, setDatasources] = useState<DataSourceSettings[] | null>(null);

  const [tasks, setTasks] = useState<TaskTableRowConfig[] | null>(null);
  const [queries, setQueries] = useState<QueryTableRowConfig[] | null>(null);

  const [tasksDataFrame, setTasksDataFrame] = useState<DataFrame | null>(null);
  const [queriesDataFrame, setQueriesDataFrame] = useState<DataFrame | null>(null);

  const [isModalOpen, setModalVisibility] = useState<boolean>(false);

  useEffect(() => {
    async function getCurrentDashboard(): Promise<any> {
      const currentDashboardUid = getDashboardUid(window.location.toString());

      console.log(currentDashboardUid)

      return getDashboardByUid(currentDashboardUid);
    }

    getCurrentDashboard()
      .then((dash) => setDashboard(dash.dashboard))
      .catch((err) => console.error(err));
  }, []);

  useEffect(() => {
    getDatasources()
      .then((datasources) => setDatasources(datasources))
      .catch((err) => console.error(err));
  }, []);

  useEffect(() => {
    if (!dashboard || !datasources) {
      return;
    }
    dashboard.panels.forEach((panel: PanelModel) => {
      const queries: QueryTableRowConfig[] = [];

      // @ts-ignore
      // TODO: move plugin id to const
      if (panel.type === 'corpglory-dataexporter-panel') {
        return;
      }

      if (!_.includes(_.values(DatasourceType), panel.datasource?.type)) {
        return;
      }

      console.log(panel)

      panel.targets?.forEach(
        (target: DataQuery) => {
          console.log('uid',target.datasource?.uid)
          const datasource = getDatasourceByUid(target.datasource?.uid);
          if (!datasource) {
            return;
          }
          queries.push({ ...target, selected: false, panel, datasource });
        }
      );

      console.log('q', queries)
      setQueries(queries);
    })
  }, [dashboard, datasources]);

  useEffect(() => {
    if (tasks === null) {
      return;
    }
    const dataFrame = getDataFrameForTaskTable(tasks);
    setTasksDataFrame(dataFrame);
  }, [tasks]);

  useEffect(() => {
    // TODO: move this function to API Service
    async function getTasks(): Promise<TaskTableRowConfig[]> {
      return queryApi<TaskTableRowConfig[]>('/task', {});
    }

    getTasks()
      .then((tasks) => setTasks(tasks))
      .catch((err) => console.error(err));
  }, []);

  useEffect(() => {
    if(queries === null) {
      return;
    }
    setQueriesDataFrame(getDataFrameForQueriesTable(queries));
  }, [queries]);


  function getDatasourceByUid(uid?: string): DataSourceSettings | undefined {
    if (_.isNil(uid)) {
      console.warn(`uid is required to get datasource`);
      return undefined;
    }
    if (datasources === null) {
      console.warn(`there is no datasources yet`);
      return undefined;
    }
    const datasource = _.find(datasources, (datasource: DataSourceSettings) => datasource.uid === uid);

    if (!datasource) {
      console.warn(`can't find datasource "${uid}"`);
    }

    return datasource;
  }

  async function onAddTaskClick(): Promise<void> {
    const selectedQueries = _.filter(queries, (query: QueryTableRowConfig) => query.selected);

    // TODO: timerange picker
    const timerange: [number, number] = [timeRange.from.unix(), timeRange.to.unix()];

    // TODO: move this function to API Service
    await queryApi('/task', {
      method: 'POST',
      data: {
        from: timerange[0] * 1000,
        to: timerange[1] * 1000,
        // @ts-ignore
        username: contextSrv.user.username,
        tasks: selectedQueries,
        url: window.location.toString(),
      },
    });

    // TODO: refresh panel (or get websocket events)

    onCloseModal();
    unselectAllQueries();
  }

  function unselectAllQueries(): void {
    if (queries === null) {
      return;
    }
    setQueries(queries.map(
      (query: QueryTableRowConfig) => ({ ...query, selected: false })
    ));
  }

  function openDatasourceModal(): void {
    setModalVisibility(true);
  }

  function onCloseModal(): void {
    setModalVisibility(false);
    unselectAllQueries();
  }

  function getDataFrameForQueriesTable(configs: QueryTableRowConfig[]): DataFrame {
    const dataFrame = toDataFrame({
      name: 'A',
      fields: [
        {
          name: 'Select',
          type: FieldType.string,
          values: _.map(
            configs,
            (config) => `data:image/svg+xml;base64,${config.selected ? SELECT_ICON_BASE_64 : UNSELECT_ICON_BASE_64}`
          ),
          config: {
            custom: {
              filterable: false,
              displayMode: 'image',
            },
            links: [
              {
                targetBlank: false,
                title: 'Select',
                url: '#',
                onClick: (event: DataLinkClickEvent) => onDatasourceSelectClick(event, configs),
              },
            ],
          },
        },
        {
          name: 'Panel',
          type: FieldType.string,
          values: _.map(configs, (config) => config.panel.title),
        },
        {
          name: 'RefId',
          type: FieldType.string,
          values: _.map(configs, (config) => config.refId),
        },
        {
          name: 'Datasource',
          type: FieldType.string,
          values: _.map(configs, (config) => config.datasource.name),
        },
      ],
    });

    const dataFrames = applyFieldOverrides({
      data: [dataFrame],
      fieldConfig: {
        overrides: [],
        defaults: {},
      },
      theme: createTheme(),
      replaceVariables: (value: string) => value,
    });
    return dataFrames[0];
  }

  function getDataFrameForTaskTable(configs: TaskTableRowConfig[]): DataFrame {
    const dataFrame = toDataFrame({
      name: 'A',
      fields: [
        {
          name: 'Time',
          type: FieldType.number,
          values: _.map(configs, (config) => convertTimestampToDate(config.timestamp)),
        },
        {
          name: 'User',
          type: FieldType.string,
          values: _.map(configs, (config) => config.user),
        },
        {
          name: 'Datasource',
          type: FieldType.string,
          values: _.map(configs, (config) => getDatasourceByUid(config.datasourceRef?.uid)?.name),
        },
        {
          name: 'Exported Rows',
          type: FieldType.number,
          values: _.map(configs, (config) => config.rowsCount),
        },
        {
          name: 'Progress',
          type: FieldType.string,
          values: _.map(configs, (config) => `${config.progress}%`),
        },
        {
          name: 'Status',
          type: FieldType.string,
          values: _.map(configs, (config) => config.status),
        },
        {
          name: 'Download CSV',
          type: FieldType.string,
          values: _.map(configs, () => `data:image/png;base64,${DOWNLOAD_ICON_BASE_64}`),
          config: {
            custom: {
              filterable: false,
              displayMode: 'image',
            },
            links: [
              {
                targetBlank: false,
                title: 'CSV link',
                // TODO: config.downloadLink
                url: 'https://chartwerk.io/',
              },
            ],
          },
        },
        {
          name: 'Delete task',
          type: FieldType.string,
          values: _.map(configs, () => `data:image/png;base64,${CLOSE_ICON_BASE_64}`),
          config: {
            custom: {
              filterable: false,
              displayMode: 'image',
            },
            links: [
              {
                targetBlank: false,
                title: 'Delete',
                url: '#',
                onClick: (event: DataLinkClickEvent) => onDeleteClick(event, configs),
              },
            ],
          },
        },
      ],
    });

    const dataFrames = applyFieldOverrides({
      data: [dataFrame],
      fieldConfig: {
        overrides: [],
        defaults: {},
      },
      theme: createTheme(),
      replaceVariables: (value: string) => value,
    });
    return dataFrames[0];
  }

  function onDeleteClick(e: DataLinkClickEvent, tasks: TaskTableRowConfig[]): void {
    // TODO: make DELETE request to the api
    const rowIndex = e.origin.rowIndex;
    const filteredTasks = _.filter(tasks, (task, idx) => idx !== rowIndex);
    setTasks(filteredTasks);
  }

  function onDatasourceSelectClick(e: DataLinkClickEvent, queries: QueryTableRowConfig[]): void {
    const rowIndex = e.origin.rowIndex;
    const updatedQueries = _.clone(queries);
    updatedQueries[rowIndex].selected = !updatedQueries[rowIndex].selected;
    setQueries(updatedQueries);
  }

  return (
    <div>
      {tasksDataFrame === null ? (
        // TODO: if datasource responds with error, display the error
        <LoadingPlaceholder text="Loading..."></LoadingPlaceholder>
      ) : (
        <div>
          <Table width={width} height={height - 40} data={tasksDataFrame} />
          <HorizontalGroup justify="flex-end">
            <Button
              variant="primary"
              aria-label="Rich history button"
              icon="plus"
              style={{ marginTop: '8px' }}
              onClick={openDatasourceModal}
            >
              Add Task
            </Button>
            <Modal title="Select Queries" isOpen={isModalOpen} onDismiss={onCloseModal}>
              {queriesDataFrame === null ? (
                // TODO: if datasource responds with error, display the error
                <LoadingPlaceholder text="Loading..."></LoadingPlaceholder>
              ) : (
                <div>
                  <Table width={width / 2 - 20} height={height - 40} data={queriesDataFrame} />
                  <HorizontalGroup justify="flex-end">
                    <Button
                      variant="primary"
                      aria-label="Add task button"
                      style={{ marginTop: '8px' }}
                      onClick={onAddTaskClick}
                      // TODO: move to function
                      disabled={!queries?.filter((query: QueryTableRowConfig) => query.selected)?.length}
                    >
                      Add Task
                    </Button>
                  </HorizontalGroup>
                </div>
              )}
            </Modal>
          </HorizontalGroup>
        </div>
      )}
    </div>
  );
}
