import React, { useState, useEffect, useContext } from 'react';

import { Table, Skeleton, Input, Tag, Modal, message } from 'antd';

import { QrcodeOutlined } from '@ant-design/icons';

import { Location, FormCreator, GlobalContext, ExportReactCSV, getExportData, Card, TableComponent, QrScanner } from './../../../../lib/';

import { CoreScripts } from './../../../../models/';

import moment from 'moment-timezone';

import Button from '../../../../lib/elements/basic/button/button';

import { Link } from 'react-router-dom';

import './reporting-dashboard.scss';

import { useHistory } from 'react-router-dom';

import MenuDashBoard from '../../../../pages/homepage-api/menu-dashboard';

// import { isPdfFile } from 'pdfjs-dist';

var genericComponents = require('./../../../../lib/modules/index');

const { Search } = Input;

/**
 * ReportingDashboard component renders the dashboard and handles patient details,
 * configuration, and form layout for generating reports.
 *
 * @param {Object} props - The component's props.
 * @param {Object} props.match - The match object containing the URL parameters.
 * @param {Object} props.CustomComponents - Custom components for rendering.
 * @param {string} props.reportId - The report ID.
 * @param {boolean} props.isFixedIndex - Determines if the index is fixed.
 * @param {Array<string>} props.dashBoardIds - The list of dashboard IDs.
 *
 * @returns {JSX.Element} The rendered ReportingDashboard component.
 */
export default function ReportingDashboard({ match, CustomComponents, reportId, isFixedIndex, dashBoardIds, barcodeFilterKey,showScanner }) {
  const [config, setConfig] = useState({});

  // State to manage the layout of the form
  const [formLayout, setFormLayout] = useState('inline');

  const [loading, setLoading] = useState(true);

  const [dashboardVisible, setDashBoardVisible] = useState(false);

  const [formContents, setformContents] = useState({});

  //In case of reports from core_script , there will be id from params
  // In case of normal menu we need to take id from props
  let id = reportId ? reportId : match.params.id;

  const { CustomModels = {} } = useContext(GlobalContext);

  const [details, setDetails] = useState([]);

  const [columns, setColumns] = useState([]); // To set columns

  const [summaryColumns, setSummaryColumns] = useState([]);

  const [patients, setPatients] = useState([]); //Patients list array

  /**
   * Fetches patient details from the server and updates the relevant state.
   * This includes input parameters, columns, summary columns, and configuration.
   *
   * @returns {Promise<void>} A promise that resolves when the patient details have been fetched and the state has been updated.
   */
  async function getPatientDetails() {
    setPatients([]);

    await CoreScripts.getRecord({ id }).then(({ result }) => {
      prepareInputParameters(result.input_parameters);

      setColumns(JSON.parse(result.display_columns));

      if (result.summary_columns) {
        setSummaryColumns(JSON.parse(result.summary_columns));
      }

      setConfig({ ...result });
    });
  }

  // useEffect(() => {
  //   if (!dashboardVisible) {
  //     refresh(false);
  //   }
  // }, [dashboardVisible]);

  /**
   *
   *
   * Manage initial render
   */

  useEffect(() => {
    getPatientDetails();
  }, []);

  /**
   * Effect hook that triggers the `getPatientDetails` function
   * whenever the `match.params.id` value changes.
   *
   * @returns {void} This hook does not return anything.
   */
  useEffect(() => {
    getPatientDetails();
  }, [match.params.id]);

  let parameters;

  /**
   * Some parameters would need binding with the model
   *
   * @param {*} inputParameters Input parameters from the report configuration.
   */

  //Prepare input parameters by mapping default values and binding models if needed
  async function prepareInputParameters(inputParameters) {
    setLoading(true);

    let urlParams = Location.search();

    parameters = JSON.parse(inputParameters);

    let formContent = {};

    parameters = await parameters.map((record) => {
      // Only if the url params does have a matching value ,
      // we should not consider the default  value

      if (urlParams[record.field]) {
        if (record.type === 'date') {
          formContent[record.field] = moment.utc(urlParams[record.field]);
        }

        // return formContent;
      } else {
        // let StartDate, EndDate;
        switch (record.default) {
          case 'startOfDay':
            formContent[record.field] = moment().utc().startOf('day'); //Start of the current day

            break;

          case 'endOfDay':
            formContent[record.field] = moment().utc().endOf('day'); // End of the current day

            break;

          case 'startOfWeek':
            formContent[record.field] = moment().utc().startOf('week').toDate();

            break;

          case 'endOfWeek':
            formContent[record.field] = moment().utc().endOf('week').toDate();

            break;

          case 'currentDate':
            formContent[record.field] = moment().utc(); // current day

            break;

          default:
            break;
        }
      }

      if (['reference-select', 'reference-search', 'select'].indexOf(record.type) !== -1) {
        // let model = "";
        let model = CustomModels[record.modelName];

        return {
          ...record,
          model,
          required: record.required,
        };
      } else {
        return {
          ...record,
          required: true,
        };
      }
    });

    // Update form content state
    setformContents(formContent);

    // Trigger form submission
    onFinish(formContent);

    setLoading(false);

    setDetails([...parameters]);
  }

  // Refresh patient details.

  function refresh() {
    getPatientDetails();
  }

  /**
   *
   * @param {*} values
   */

  const onFinish = async (values) => {
    setLoading(true);

    // // Check if the dashboard is visible and both start and end values are provided
    // If true, proceed with hiding the dashboard by setting dashboardVisible to false
    if (dashboardVisible && values.start && values.end) {
      setDashBoardVisible((prev) => {
        if (!prev) return prev; // Prevent unnecessary updates

        return false;
      });
    }
    // Cheacking if there is data and making the data url friendly, ie, if there is date in url
    if (config.input_parameters) {
      let urlsToUpdate = {};

      let parameterValue = JSON.parse(config.input_parameters);

      // Variable to store/update the form initial Values

      let formContent = {};

      parameters = await parameterValue.map((parameter) => {
        //Getting url friendly value by matching the url values and input_parameter values
        let urlFriendlyValue = values[parameter.field];

        // Cheacking if the typr is date
        if (parameter.type === 'date') {
          let field = parameter.field;
          // Preparing formContent
          formContent = {
            ...formContent,
            [field]: urlFriendlyValue,
          };

          // Converting the urlFriendlyValue to the format to be passed to date piker
          urlFriendlyValue = moment(urlFriendlyValue).format('YYYY-MM-DD');

          urlsToUpdate[parameter.field] = urlFriendlyValue;
        }
      });

      setformContents(formContent);

      Location.search({ ...urlsToUpdate });
    }

    if (values.date) {
      values.date = moment(values.date).format('YYYY-MM-DD');
      //   getPatientDetails()
    }

    let formBody = {
      body: values,
    };

    await CoreScripts.getReportingLisitng(id, formBody).then((result) => {
      //These changes done when the reporting dashboard breaks if there is no data,
      // this happen due to the format of data coming in 2 different cases and following are the cases
      // In case of nura, by default the result comes as follows

      let resultDetails = result[0];

      // In case of Your centre, by default the result comes as follows

      if (result?.result && result?.result[0]) {
        resultDetails = result.result[0];
      }
      setPatients(resultDetails);

      setLoading(false);

      return;
    });
  };

  let model = {
    fields: details,
  };

  return (
    <Card className="reporting-dashboard card card-shadow">
      {/** If dashBoardIds exist and contain elements, render MenuDashBoard*/}

      {/* Page Header */}
      {/* <div className="page-header">
                <div>
                    <Title style={{ marginBottom: '0px' }} level={4}>
                        {config.caption || 'Report'}
                    </Title>
                </div>

                <div className="right">
                    <div className="date-and-fltr">
                        <Button onClick={refresh} type="secondary" size={'small'}>
                            <ReloadOutlined />
                        </Button>
                    </div>
                </div>
            </div> */}
      {/* Page Header Ends */}
      {dashBoardIds?.length > 0 ? (
        <MenuDashBoard
          dashBoardIds={dashBoardIds} //Pass the available dashboard IDs to the componen
          callback={(record) => {
            if (record.other_details) {
              // Convert the other_details string to a JSON object
              let json = JSON.parse(record.other_details);
              id = json.script_id;
              // menudashBoardVisible = true;
              setDashBoardVisible(true); // Show the dashboard component
              getPatientDetails(); // Fetch and update patient details based on the selected item
              // setDashBoard(true);
            }
          }}
        ></MenuDashBoard>
      ) : null}

      {/* Content Below */}
      {loading ? (
        <>
          <Skeleton active />
        </>
      ) : (
        <>
          <div>
            {/* <Card className="form-card" style={{ padding: '10px 10px' }}> */}
            {details && details[0] && !loading ? (
              <FormCreator
                {...formLayout}
                layout={formLayout}
                initialValues={{
                  layout: formLayout,
                }}
                styles={{ paddingRight: '15px', alignItems: 'center' }}
                fields={details}
                formContent={formContents}
                // formContent={{ [model]: {} }}
                modelIndex="requestId"
                model={model}
                onSubmit={onFinish}
                callback={() => {
                  // history.goBack();
                }}
              />
            ) : null}
            {/* </Card> */}
          </div>

          {/** GuestList component start*/}
          <GuestList
            patients={patients}
            columns={columns}
            summaryColumns={summaryColumns}
            isFixedIndex={isFixedIndex}
            showScanner={showScanner}
            barcodeFilterKey={barcodeFilterKey}
            CustomComponents={{ ...CustomComponents, ...genericComponents }}
            refresh={refresh}
          />
          {/** GuestList component end*/}
        </>
      )}
    </Card>
  );
}

/**
 *
 * @param root0
 * @param root0.patients
 * @param root0.CustomComponents
 * @param root0.summaryColumns
 * @param root0.refresh
 * @param root0.isFixedIndex
 * @returns {*}
 */
//Renders a table displaying a list of patients with dynamic columns
function GuestList({ patients, columns, CustomComponents, refresh, isFixedIndex, barcodeFilterKey,showScanner }) {
  var [query, setQuery] = useState('');

  const [exportData, setExportData] = useState({});

  // const [data, setData] = useState([]);

  //visibility of the QR scanner modal.
  const [isScannerVisible, setScannerVisible] = useState(false);

  // Stores the patients filtered specifically by QR scan match.
  const [filteredPatients, setFilteredPatients] = useState([]); // Show all initially

  // patient object to redirect to upon successful QR scan.
  const [redirectPatient, setRedirectPatient] = useState(null);

  let history = useHistory();

  const { isMobile, dispatch } = useContext(GlobalContext);

  const getRedirectLink = (entry, record) => {
    let redirectLink = entry.redirect_link;
    if (entry.replace_variables) {
      entry.replace_variables.forEach((replacement) => {
        const value = record[replacement.field] || '';
        redirectLink = redirectLink.replace(new RegExp(`@${replacement.field};`, 'g'), value);
      });
    }
    return redirectLink;
  };

  // const [view, setView] = useState(isMobile ? true : false); //Need to check this condition
  const cols = [
    ...[
      {
        title: '#',
        dataIndex: 'index',
        render: (value, item, index) => index + 1,
        key: 'ColumnIndex',
        fixed: isFixedIndex ? 'left' : null,
      },
    ],
    ...columns.map((entry) => {
      // if (entry.sort) {
      //     return {
      //         render: (record) => {

      //             if (entry.render) {

      //                 return entry.render(record);
      //             } else {
      //                 return record[entry.dataIndex]
      //             }
      //         },
      //         title: entry.title,
      //         key: entry.field,
      //         sorter: (a, b) => entry.sort(a, b),
      //         sortDirections: ['ascend', 'descend', 'ascend'],
      //     };
      // } else {
      return {
        render: (record) => {
          /** We can have x types of components that is to be rendered here */

          /**1. Column Data */

          /**2. Action  */

          /**3. Custom Component - In future .   */

          if (entry.render) {
            return entry.render(record);

            // The type of component can be differentiated by type/ we can also reuse
            // any field present in the columns to avoid any additional field
          } else if (entry.type === 'link') {
            //Cheacking type of action to be done ie,If it contains a type then it will match with the record
            // for example initally we are implementing it for a type link
            // ie, we will return a link in query with the field as link and type link in display_columns
            //So here we match the field returned by query with the type in display_columns

            if (record[entry.field]) {
              return (
                <a href={record[entry.field]} target="_blank" rel="noopener noreferrer">
                  View
                </a>
              );
            }
          } else if (entry.field === 'action') {
            let redirectLink = entry.redirect_link;

            // The variables to be replaced can be maintained
            // as a configuration in the entry or the column configuration

            // We iterate through all the variables that are present in the configuration
            // and replace the link to generate the final link

            entry.replace_variables.forEach((replacement) => {
              redirectLink = redirectLink.replace(new RegExp('@' + replacement.field + ';', 'g'), record[replacement.field]);
            });

            return <Link to={`${redirectLink}`}>View</Link>;
          } else if (entry.field === 'custom') {
            // Make all the components in modules available for use in custom column of core script
            // var genericComponents = require('./../../../../../../../nura-api-new/nura-desk/src/modules');
            var genericComponents = CustomComponents;

            // Arrive the component name
            let componentName = entry.component;

            let LoadedComponent = null;
            // If there is custom components mensioned in the display_columns,
            // then matching the custom components with the generic components
            if (componentName) {
              if (componentName && genericComponents[componentName]) {
                LoadedComponent = genericComponents[componentName];
              }
            }

            let propValue = {};
            // If there is props value
            if (entry.props) {
              // Looping the props from the props mensioned in display_columns,
              // Matching the field of record props field with the and return the
              entry.props.forEach((values) => {
                // Matching the fields of record with the props field
                let valueCreation = record[values.field];
                // Returning the values of field matched by fields
                propValue[values.value] = valueCreation;
              });
            }

            return (
              <LoadedComponent
                // Configuration will define
                {...entry.config}
                callback={() => {
                  refresh();
                }}
                // record={record}

                {...record}
                // assigning the props
                {...propValue}
              />
            );
          } else {
            // Check if both `color_code` exists in the record and `enableColor` is true
            if (record.color_code && entry.enableColor) {
              // If the column type is 'tag', render the field inside an Ant Design <Tag> with color
              if (entry.columnType === 'tag') {
                return <Tag color={record.color_code}>{record[entry.field]}</Tag>;

                // If the column type is 'span', render the field inside a <span> with inline color style
              } else if (entry.columnType === 'span') {
                return <span style={{ color: record.color_code }}>{record[entry.field]}</span>;
              }
            } else {
              // If either `color_code` or `enableColor` is missing/false, return the field value without styling
              return record[entry.field];
            }
          }
        },
        field: entry.field,
        title: entry.title,
        key: entry.field,
        fixed: entry.isFixedColumn ? entry.isFixedColumn : null, // Conditionally setting the 'fixed' key to 'left' if 'isColumnStatic' is true; otherwise, setting it to null.
        // Check if filtering is enabled and patients is an array
        filters:
          entry.isFilterEnabled && Array.isArray(patients)
            ? [...new Set(patients.map((item) => item[entry.field]).filter(Boolean))].map((value) => ({ text: value, value }))
            : null,
        // Apply the filter only if it's enabled for the column
        onFilter: entry.isFilterEnabled ? (value, record) => record[entry.field] === value : null,
        // Apply the filter search
        filterSearch: entry.isFilterEnabled ? entry.isFilterEnabled : false,
        exportDefinition: (record) => {
          //Custom components should not be downloaded
          // return entry.field === 'custom' ? null : record[entry.field];
          if (entry.field === 'custom') {
            // Find the field key in props that corresponds to 'description'
            const description = entry.props?.find((p) => p.value === 'description')?.field;

            // Return the value from record.props if it exists
            return description && record[description] ? record[description] : null;
          }

          return record[entry.field];
        },
      };
      // }
    }),
    // ...[
    //     {
    //         title: '',
    //         key: 'action',
    //         render: (text, record) => {
    //             let detail = model.slice(0, model.length - 1);

    //             return (
    //                 <Space size="middle">
    //                     {!schema.hideView && !actions.length ? <Link to={`/${city}/${model}/${text.id}`}>View</Link> : null}

    //                     {actions.map((action) => (
    //                         <Link to={action.url(record)}>{action.caption}</Link>
    //                     ))}
    //                 </Space>
    //             );
    //         },
    //     },
    // ],

    // ...[
    //     {
    //         title: '',
    //         key: 'action',
    //         render: (text, record) => {
    //             let detail = model.slice(0, model.length - 1);

    //             return (
    //                 <Link to={`${menu.path.replace(':id',visitid)}?op_no=${OpNo}`}>
    //                     <Button size={'small'}>
    //                         <PlayCircleOutlined />
    //                         Go to Menu
    //                     </Button>
    //                 </Link>
    //             );
    //         },
    //     },
    // ],
  ];

  /**
   *
   * @param {*} result
   */

  // function changeView(result) {
  //     setView(result);
  // }

  /**
   *
   * @param {*} event
   */

  function onSearch(event) {
    setQuery(event.target.value);
  }

  /**
   *
   */

  useEffect(() => {
    //Cheaking if there is patient data exists
    if (patients) {
      let data = patients?.map((entry) => {
        entry.rowIndex = entry.opb_id;

        entry.dispatch = dispatch;

        return entry;
      });

      // setData(data);

      // Define export data
      let exportDatas = getExportData(patients, cols);

      if (exportDatas.exportDataColumns.length && exportDatas.exportDataHeaders.length) {
        setExportData({ exportDatas });
      }
    }
  }, [patients]);

  let filtered;

  if (patients) {
    filtered = patients.filter((record) => {
      if (query) {
        // Keys
        let keys = Object.keys(record);

        let flag = false;

        keys.forEach((key) => {
          let ele = record[key];

          if (ele && typeof ele === 'string' && ele.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
            flag = true;
          }
        });

        /**Will return flag */
        return flag;
      } else {
        return true;
      }
    });
  }

  /**
   * Checks for a match in the filtered patient list based on a scanned code,
   * updates the relevant state if a match is found, and redirects to the
   * patient's detail page. Displays a warning if no match is found.
   *
   * @param {string} code - The scanned code to match against a specific field of each patient.
   */

  const handleScanSuccess = (code) => {
    // Filters patients based on the scanned code and the selected barcode key(using attributes 'barcodeFilterKey')
    const matched = filtered.filter((patient) => patient[barcodeFilterKey] === code);

    if (matched.length) {
      const patient = matched[0];
      setFilteredPatients(matched);
      setRedirectPatient(matched);
      message.success(`Match found for ${code}, redirecting...`);

      const actionColumn = columns.find((col) => col.field === 'action');
      if (actionColumn) {
        const redirectLink = getRedirectLink(actionColumn, patient);
        history.push(redirectLink);
      }
    } else {
      Modal.warning({
        title: 'Guest Not Found',
        content: `No match for scanned code: ${code}`,
      });
    }
  };

  return (
    <>
      <div className="table-header">
        <div>
          <Search placeholder="Enter Search Value" allowClear onChange={onSearch} />

          {/* <p className="size-hint">{patients.length} records.</p> */}
        </div>

        <div className="table-right">
          {/* QR Scan start */}
          {showScanner ? (
          <Button size="small" type="primary" icon={<QrcodeOutlined />} onClick={() => setScannerVisible(true)}>
            Scan QR
          </Button>):null}

          <Modal open={isScannerVisible} title="Scan QR Code" footer={null} onCancel={() => setScannerVisible(false)} destroyOnClose>
            <QrScanner onScanSuccess={handleScanSuccess} onClose={() => setScannerVisible(false)} />
          </Modal>

          <div>
            {/* QR Scan End */}
            {/*table data export to csc component*/}
            {exportData.exportDatas && (
              <ExportReactCSV headers={exportData.exportDatas.exportDataHeaders} csvData={exportData.exportDatas.exportDataColumns} />
            )}
          </div>
        </div>
      </div>

      <div>
        {/* {view ? (
                    <>
                        <CardList dataSource={data} columns={columns} />
                    </>
                ) : (
                    <> */}
        <Card>
          <TableComponent
            size="small"
            scroll={{ x: true }}
            rowKey={(record) => record.OpNo}
            dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
            columns={cols}
            pagination={false}
            summary={(pageData) => {
              // Variable to save the summary data
              let summary = {};

              let summaryColumns = [
                { field: 'opb_amt', title: 'Amount' },
                { field: 'opb_netamt', title: 'Net Amount' },
              ];

              let tableColumns = cols;

              // Creating a copy of columns to append the summary configuration that is needed to set
              tableColumns.forEach((record, index) => {
                summaryColumns.forEach((inner) => {
                  if (record.field === inner.field) {
                    tableColumns[index].summary = inner;
                  }
                });
              });

              // Initialize
              summaryColumns.map((item) => {
                return (summary[item.field] = 0);
              });

              // Find the total
              summaryColumns.map((item) => {
                pageData.forEach((entry) => {
                  return (summary[item.field] = summary[item.field] + entry[item.field]);
                });
              });

              return (
                <>
                  <Table.Summary.Row>
                    {tableColumns.map((column, key) => {
                      return <Table.Summary.Cell key={key}>{column.summary ? <>{summary[column.summary.field]}</> : null}</Table.Summary.Cell>;
                    })}
                  </Table.Summary.Row>
                </>
              );
            }}
          />
          {/*If patient data exists show the number else to 0 */}
          <p className="size-hint">{patients ? patients.length : 0} records. </p>
        </Card>
        {/* </> */}
        {/* )} */}
      </div>
    </>
  );
}

// //Mobile view card Section
// function CardList({ dataSource, url }) {
//     const { user = {}, dispatch } = useContext(GlobalContext);

//     function onClick(item) {
//         Location.navigate({
//             url: `/lab-detail/${item.BillID}`,
//         });

//         dispatch({ type: 'index', payload: item.rowIndex });
//     }

//     return dataSource.map((item, index) => {
//         // to={`/lab-detail/${item.BillID}`}
//         return (
//             <div
//                 key={index}
//                 className="report-item"
//                 onClick={() => {
//                     onClick(item);
//                 }}
//             >
//                 <GuestCard record={item} />
//             </div>
//         );
//     });
// }

// function GuestCard({ record }) {
//     return (
//         <Card className="card vehicle-card">
//             <div className="card">
//                 <h2 className="title">{record.PName}</h2>

//                 <h4 className="values">{record.OpNo}</h4>

//                 <h3 className="values">{record.Test}</h3>

//                 <h3 className="values">Primary Result : {record.PrimaryResult || 'Pending'}</h3>

//                 <Text type="secondary">{record.Mobile}</Text>

//                 <h4 className="values">{record.Date}</h4>
//             </div>
//         </Card>
//     );
// }
