import { t } from '@lingui/macro';
import { Button, Input, Table, Tag, DatePicker, Form, Modal, Select, Spin, message, Upload } from 'antd';
import React, { useContext, useEffect, useRef, useState } from 'react';
import type { GetRef } from 'antd';
import { Layout } from 'antd';
import {
  DownloadOutlined, CheckCircleOutlined,
  ClockCircleFilled,
} from '@ant-design/icons';
import styled from 'styled-components';
const { Sider, Content } = Layout;
import { baseURL } from "request/api";
import { useHotkeys } from "react-hotkeys-hook";
import { Viewer } from '@react-pdf-viewer/core';
import { SbtPageHeader } from 'components/page-header';
import { UploadOutlined } from '@ant-design/icons';
import type { GetProp, UploadFile, UploadProps } from 'antd';
import 'react-json-view-lite/dist/index.css';

type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];

const ENABLE_REVIEW = false;


// Import the styles
import '@react-pdf-viewer/core/lib/styles/index.css';


const siderStyle: React.CSSProperties = {
  backgroundColor: '#fafafa',
  padding: 10,
  width: 200,
};


const StyledTable = styled(Table)`
  & .sbt-table-cell {
    padding: 4px!important;
  }
`;

type InputRef = GetRef<typeof Input>;
type FormInstance<T> = GetRef<typeof Form<T>>;

const EditableContext = React.createContext<FormInstance<any> | null>(null);

interface Item {
  key: string;
  accuracy: number;
  revised: string;
  action: string;
}

interface EditableRowProps {
  index: number;
}

const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
  const [form] = Form.useForm();
  return (
    <Form form={form} component={false}>
      <EditableContext.Provider value={form}>
        <tr {...props} />
      </EditableContext.Provider>
    </Form>
  );
};

interface EditableCellProps {
  title: React.ReactNode;
  editable: boolean;
  children: React.ReactNode;
  dataIndex: keyof Item;
  record: Item;
  handleSave: (record: Item) => void;
}


const EditableCell: React.FC<EditableCellProps> = ({
  title,
  editable,
  children,
  dataIndex,
  record,
  handleSave,
  ...restProps
}) => {
  const [editing, setEditing] = useState(false);
  const inputRef = useRef<InputRef>(null);
  const form = useContext(EditableContext)!;

  useEffect(() => {
    if (editing) {
      inputRef.current!.focus();
    }
  }, [editing]);

  const toggleEdit = () => {
    setEditing(!editing);
    form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  };

  const save = async () => {
    try {
      const values = await form.validateFields();

      toggleEdit();
      handleSave({ ...record, ...values });
    } catch (errInfo) {
      console.log('Save failed:', errInfo);
    }
  };

  let childNode = children;

  if (editable) {
    childNode = editing ? (
      <Form.Item
        style={{ margin: 0 }}
        name={dataIndex}
        rules={[
          {
            required: true,
            message: `${title} is required.`,
          },
        ]}
      >
        <Input ref={inputRef} onPressEnter={save} onBlur={save} />
      </Form.Item>
    ) : (
      <div className="editable-cell-value-wrap" style={{ paddingRight: 24 }} onClick={toggleEdit}>
        {children}
      </div>
    );
  }

  return <td {...restProps}>{childNode}</td>;
};

// type EditableTableProps = Parameters<typeof Table>[0];

const FileCard = ({ file, isSelected, onClick, setIsReasonModalOpen }) => {
  const fileName = file["File Name"];

  return (
    <div style={{
      border: '1px solid #ccc',
      width: '200px',
      backgroundColor: isSelected ? '#d4ecff' : '#fff',
      padding: '4px 8px',
      marginRight: '4px',
      marginTop: '2px',
      position: 'relative',
      height: '100px',
      overflow: 'hidden',
    }} onClick={onClick}>
      <div>
        <span style={{
          fontSize: '12px',
          color: '#333',
          fontWeight: 'bold',
          padding: '4px 8px',
          cursor: 'default',
        }}>{file["Doc Type"].toUpperCase()}</span>
        <span style={{
          fontSize: '12px',
          color: '#aaa',
          fontWeight: 'bold',
          padding: '4px 8px',
          cursor: 'default',
          maxWidth: '50px',
          overflow: 'hidden',
          textOverflow: 'ellipsis',
        }}>
          {fileName ? fileName.substring(0, 25).replace("temp_", "") : fileName}
        </span>
      </div>
      <div style={{
        padding: '4px',
        position: 'absolute',
        bottom: 2,
        right: 2,
      }}>
        <Button style={{
          margin: '4px 2px',
        }}
          onClick={() => {
            setIsReasonModalOpen(true);
          }}
        >
          Review
        </Button>
        <Button style={{
          margin: '4px 2px',
        }} onClick={() => {
          const downloadUrl = file["File URL"];
          window.open(downloadUrl, '_blank');
        }}>
          <DownloadOutlined />
        </Button>
      </div>
    </div>
  );

};

const fetchRequest = async (id) => {
  const token = localStorage.getItem('sbt-token') || '';
  const response = await fetch(`${baseURL}/ctel/request/${id}/`, {
    method: 'GET',
    headers: {
      "Authorization": `${JSON.parse(token)}`
    }
  });
  return await (await response.json()).subscription_requests[0];
};

const InferencePage = () => {
  const [invoiceFiles, setInvoiceFiles] = useState<UploadFile[]>([]);
  const [imei1Files, setImei1Files] = useState<UploadFile[]>([]);
  const [imei2Files, setImei2Files] = useState<UploadFile[]>([]);
  const [uploading, setUploading] = useState(false);
  const [responseData, setResponseData] = useState(null);
  const [finishedProcessing, setFinishedProcessing] = useState(false);

  const handleUpload = () => {
    const formData = new FormData();
    if (invoiceFiles.length > 0) {
      formData.append('invoice_file', invoiceFiles[0] as FileType);
    }
    if (imei1Files.length > 0) {
      formData.append('imei_files', imei1Files[0] as FileType);
    }
    if (imei2Files.length > 0) {
      formData.append('imei_files', imei2Files[0] as FileType);
    }
    formData.append('is_test_request', 'true');
    setUploading(true);
    setResponseData(null);
    const token = localStorage.getItem('sbt-token') || '';
    fetch(`${baseURL}/ctel/images/process_sync/`, {
      method: 'POST',
      body: formData,
      headers: {
        "Authorization": `${JSON.parse(token)}`
      }
    })
      .then(async (res) => {
        const data = await res.json();
        if (data["status"] != "200") {
          setResponseData(null);
          return;
        }
        loadRequestById(data["request_id"]);
        setFinishedProcessing(true);
        return data;
      })
      .then(() => {
        message.success('Upload successfully.');
      })
      .catch((e) => {
        console.log(e);
        message.error('Upload failed.');
      })
      .finally(() => {
        setUploading(false);
      });
  };
  const [loading, setLoading] = useState(false);
  const [isReasonModalOpen, setIsReasonModalOpen] = useState(false);
  const [selectedFileId, setSelectedFileId] = useState(0);
  const [selectedFileData, setSelectedFileData] = useState(null);
  const [selectedFileName, setSelectedFileName] = useState(null);
  const [currentRequest, setCurrentRequest] = useState(null);
  const [totalRequests, setTotalPages] = useState(0);
  const [dataSource, setDataSource] = useState([]);

  const setAndLoadSelectedFile = async (requestData, index) => {
    setSelectedFileId(index);
    if (!requestData["Files"][index]) {
      setSelectedFileData("FAILED_TO_LOAD_FILE");
      return;
    };
    const fileName = requestData["Files"][index]["File Name"];
    const fileURL = requestData["Files"][index]["File URL"];
    const response = await fetch(fileURL);
    if (response.status === 200) {
      setSelectedFileName(fileName);
      setSelectedFileData(fileURL);
      console.log("Loading file: " + fileName);
      console.log("URL: " + fileURL);
    } else {
      setSelectedFileData("FAILED_TO_LOAD_FILE");
    }
  };

  const loadRequestById = (requestID) => {
    setLoading(true);
    const requestData = fetchRequest(requestID);
    requestData.then(async (data) => {
      if (data) setCurrentRequest(data);
      const predicted = (data && data["Reviewed Result"]) ? data["Reviewed Result"] : {};
      const revised = (data && data["Reviewed Result"]) ? data["Reviewed Result"] : {};
      const keys = Object.keys(predicted);
      const tableRows = [];
      for (let i = 0; i < keys.length; i++) {
        let instance = {};
        instance["key"] = keys[i];
        instance["predicted"] = predicted[keys[i]];
        instance["revised"] = revised[keys[i]];
        tableRows.push(instance);
      }
      setDataSource(tableRows);
      setLoading(false);
      setAndLoadSelectedFile(data, 0);
    }).finally(() => {
      setLoading(false);
    });
  };

  const components = {
    body: {
      row: EditableRow,
      cell: EditableCell,
    },
  };

  // "Key", "Accuracy", "Revised"
  interface DataType {
    key: string;
    accuracy: number;
    revised: string;
  };

  const updateRevisedData = async (newRevisedData: any) => {
    const requestID = newRevisedData.request_id;
    const token = localStorage.getItem('sbt-token') || '';
    await fetch(`${baseURL}/ctel/request/${requestID}/`, {
      method: 'POST',
      headers: {
        "Authorization": `${JSON.parse(token)}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        "reviewed_result": newRevisedData
      }),
    }).catch((error) => {
      console.log(error);
      message.error("Could not update revised data");
    });
  };

  const handleSave = (row: DataType) => {
    const newData = [...dataSource];
    const index = newData.findIndex((item) => row.key === item.key);
    const item = newData[index];
    newData.splice(index, 1, {
      ...item,
      ...row,
    });
    setDataSource(newData);
    const newRevisedData = {};
    for (let i = 0; i < newData.length; i++) {
      newRevisedData[newData[i].key] = newData[i].revised;
    }
    updateRevisedData(newRevisedData).then(() => {
      // "[Is Reviewed]" => true
      setCurrentRequest({
        ...currentRequest,
        ["Is Reviewed"]: true,
      })
    })
  };

  const submitRevisedData = async () => {
    const newData = [...dataSource];
    const newRevisedData = {};
    for (let i = 0; i < newData.length; i++) {
      newRevisedData[newData[i].key] = newData[i].revised;
    }
    console.log(currentRequest)
    updateRevisedData(newRevisedData).then(() => {
      // "[Is Reviewed]" => true
      setCurrentRequest({
        ...currentRequest,
        ["Is Reviewed"]: true,
      })
    })
  };


  const defaultColumns = [
    {
      title: 'Key',
      dataIndex: 'key',
      key: 'key',
      width: 200,
    },
    {
      title: 'Predicted',
      dataIndex: 'predicted',
      key: 'predicted',
    },
    {
      title: (<div style={{
        width: 120,
        display: 'flex',
        lineHeight: '32px',
        marginLeft: 10,
      }}>Revised&nbsp;&nbsp;
        {ENABLE_REVIEW && <Button
          onClick={() => {
            if (!dataSource || !dataSource.length) return;
            setDataSource(dataSource.map(item => {
              item.revised = item.predicted;
              return item;
            }));
            setTimeout(() => {
              submitRevisedData();
            }, 1000);
          }}
        >
          Copy Predicted
        </Button>}
      </div>),
      dataIndex: 'revised',
      key: 'revised',
      editable: ENABLE_REVIEW,
    },
  ];


  const columns = defaultColumns.map((col) => {
    if (!col.editable) {
      return col;
    }
    return {
      ...col,
      onCell: (record: DataType) => ({
        record,
        editable: col.key != "request_id" && col.editable,
        dataIndex: col.dataIndex,
        title: col.title,
        handleSave,
      }),
    };
  });
  const fileExtension = selectedFileName ? selectedFileName.split('.').pop() : '';

  return (
    <>
      <div style={{
        height: '100%',
        position: 'relative',
      }}>
        <SbtPageHeader
          title={t`Inference`}
        />
        <div style={{
          display: 'flex',
          flexDirection: 'row',
        }}>
          <div style={{
            paddingTop: "0.5rem",
            padding: "0.5rem",
            height: "80px",
          }}>
            <Upload
              onRemove={(file) => {
                if (finishedProcessing) return;
                setInvoiceFiles([])
              }}
              beforeUpload={(file) => {
                if (finishedProcessing) return;
                setInvoiceFiles([file])
                return false;
              }}
              fileList={invoiceFiles}
            >
              Invoice: <Button disabled={finishedProcessing} icon={<UploadOutlined />}>Select Image/PDF</Button>
            </Upload>
          </div>
          <div style={{
            paddingTop: "0.5rem",
            padding: "0.5rem",
            height: "80px",
          }}>
            <Upload
              onRemove={(file) => {
                if (finishedProcessing) return;
                setImei1Files([])
              }}
              beforeUpload={(file) => {
                if (finishedProcessing) return;
                setImei1Files([file])
                return false;
              }}
              fileList={imei1Files}
            >
              IMEI 1: <Button disabled={finishedProcessing} icon={<UploadOutlined />}>Select Image</Button>
            </Upload>
          </div>
          <div style={{
            paddingTop: "0.5rem",
            padding: "0.5rem",
            height: "80px",
          }}>
            <Upload
              onRemove={(file) => {
                if (finishedProcessing) return;
                setImei2Files([])
              }}
              beforeUpload={(file) => {
                if (finishedProcessing) return;
                setImei2Files([file])
                return false;
              }}
              fileList={imei2Files}
            >
              IMEI 2: <Button disabled={finishedProcessing} icon={<UploadOutlined />}>Select Image</Button>
            </Upload>
          </div>
          <div style={{
            paddingTop: "0.5rem",
            padding: "0.5rem",
            height: "80px",
            display: 'flex',
            flexDirection: 'row',
          }}>
            {!finishedProcessing && <Button
              type="primary"
              onClick={handleUpload}
              disabled={imei1Files.length === 0 && imei2Files.length === 0}
              loading={uploading}
            >
              {uploading ? 'Uploading' : 'Process Data'}
            </Button>}
            {finishedProcessing && <Button
              type="primary"
              onClick={() => {
                setFinishedProcessing(false);
                setResponseData(null);
                setInvoiceFiles([]);
                setImei1Files([]);
                setImei2Files([]);
              }}
            >
              Reset
            </Button>}
          </div>
        </div>
        <div
          style={{ height: '100%', position: 'absolute', top: 0, left: 0, width: '100%', background: "#00000033", zIndex: 1000, display: loading ? 'block' : 'none' }}
        >
          <Spin spinning={true} style={{
            position: 'absolute',
            top: '50%',
            left: '50%',
            marginTop: -12,
            marginLeft: -12,
            width: 24,
            height: 24,
            borderRadius: '50%',
          }} size='large' />
        </div>
        <Layout style={{
          overflow: 'auto',
          width: '100%',
          height: '100%',
          maxWidth: '100%',
          minHeight: '70%',
          maxHeight: '70%',
          display: 'flex',
          padding: '8px',
        }}>
          <Content style={{
            textAlign: 'center',
            color: '#fff',
            backgroundColor: '#efefef',
            height: '100%',
            display: 'flex',
            flexDirection: 'row',
          }}>
            {currentRequest?.Files?.length && <div
              style={{
                width: "200px",
                display: "flex",
                flexDirection: "column",
                flexGrow: 0,
              }}>
              <h2
                style={{
                  color: "#333",
                  padding: 10,
                  fontWeight: 'bold',
                  fontSize: 18,
                  textTransform: 'uppercase'
                }}
              >Files ({currentRequest?.Files?.length})</h2>
              {currentRequest?.Files.map((file, index) => (
                <FileCard key={index} file={file} isSelected={index === selectedFileId} onClick={
                  () => {
                    setAndLoadSelectedFile(currentRequest, index);
                  }
                } setIsReasonModalOpen={setIsReasonModalOpen} />
              ))}
            </div>}
            {selectedFileData && <div style={{
              border: "1px solid #ccc",
              flexGrow: 1,
              height: '100%',
            }}>
              {selectedFileData === "FAILED_TO_LOAD_FILE" ? <p style={{ color: "#333" }}></p> : (fileExtension === "pdf" ? (<Viewer
                fileUrl={selectedFileData}
              />) : <div style={{
                height: "100%",
                width: "100%",
                overflow: "auto",
              }}><img width={"100%"} src={selectedFileData} alt="file" /></div>)}
            </div>}
          </Content>
          <Sider width="400px" style={siderStyle}>
            <div>
              <Input size='small' addonBefore="Request ID" style={{ marginBottom: "4px" }} readOnly value={currentRequest ? currentRequest.RequestID : ""} />
              <Input size='small' addonBefore="Redemption" style={{ marginBottom: "4px" }} readOnly value={currentRequest?.RedemptionID ? currentRequest.RedemptionID : ""} />
              <Input size='small' addonBefore="Uploaded date" style={{ marginBottom: "4px" }} readOnly value={currentRequest ? currentRequest.created_at : ""} />
              <Input size='small' addonBefore="Request time" style={{ marginBottom: "4px" }} readOnly value={currentRequest ? currentRequest["Client Request Time (ms)"] : ""} />
              <Input size='small' addonBefore="Processing time" style={{ marginBottom: "4px" }} readOnly value={currentRequest ? currentRequest["Server Processing Time (ms)"] : ""} />
              <div style={{ marginBottom: "8px", marginTop: "8px", display: "flex" }}>
                {currentRequest && (currentRequest["Is Reviewed"] ? <Tag icon={<CheckCircleOutlined />} color="success" style={{ padding: "4px 16px" }}>
                  Reviewed
                </Tag> : <Tag icon={<ClockCircleFilled />} color="warning" style={{ padding: "4px 16px" }}>
                  Not Reviewed
                </Tag>)}
              </div>
            </div>
          </Sider>
        </Layout>
        <Modal
          title={t`Review`}
          open={isReasonModalOpen}
          width={700}
          onOk={
            () => {

            }
          }
          onCancel={
            () => {
              setIsReasonModalOpen(false);
            }
          }
        >
          <Form
            style={{
              marginTop: 30,
            }}
          >
            <Form.Item
              name='reason'
              label={t`Reason for bad quality:`}
              style={{
                marginBottom: 10,
              }}
            >
              <Select
                placeholder='Select a reason'
                style={{ width: 200 }}
                options={[
                  { value: 'invalid_image', label: t`Invalid image` },
                  { value: 'missing_information', label: t`Missing information` },
                  { value: 'too_blurry_text', label: t`Too blurry text` },
                  { value: 'too_small_text', label: t`Too small text` },
                  { value: 'handwritten', label: t`Handwritten` },
                  { value: 'recheck', label: t`Recheck` },
                ]}
              />
            </Form.Item>
          </Form>
        </Modal>
        <StyledTable components={components}
          rowClassName={() => 'editable-row'}
          bordered dataSource={dataSource} columns={columns}
        />
      </div>
    </>
  );
};

export default InferencePage;
