import { useEffect, useState } from 'react';
import Button from 'react-bootstrap/Button';
import { createRequest, Request } from '../../api/Requests';
import { getPart, getParts } from '../../api/Parts';
import { createNewPart } from '../RequestForm/RequestFormHelpers';
import { User } from '../../api/Users';
import { useAuth } from '../../auth/AuthProvider';
import { Notification, createNotification } from '../../api/Notifications';
import { getFormattedTeamName, getTeam } from '../../api/Teams';
import { Form, InputGroup, Modal, Table } from 'react-bootstrap';
import { Icon } from '../shared/Icon';
import { useMediaQuery } from 'react-responsive';
import { breakpoints } from '../../utils/BootstrapHelper';
import { useToast } from '../Toast/ToastContext';
import isUrlHttp from 'is-url-http';
import { parse } from 'tldts';

// combines part and request so one form can get the info for the two
export type PartRequest = {
  student_id?: number;
  team_id?: number;
  supplier_id?: number;
  status: string;
  quantity: number;
  url: string;
  description: string;
  price: number;
  part_id?: number;
  part_num?: string;
};

type PartRequestFormErrors = {
  [x: string]: any;
  [index: number]: Partial<Record<keyof PartRequest, boolean>>;
};

type RequestFormProps = {
  selectedUser?: User | null; // Accepts a user prop that can be null
  onRequestSubmit: () => void;
};

export default function RequestForm({
  selectedUser,
  onRequestSubmit,
}: RequestFormProps) {
  const { user } = useAuth();
  const _user = selectedUser ?? user; // user auth hook if user not passed in
  const [studentId, setStudentId] = useState<number | null>(null);
  const [teamId, setTeamId] = useState<number | null>(null);
  const [isConfirming, setIsConfirming] = useState(false);
  const [formErrors, setFormErrors] = useState<PartRequestFormErrors[]>([]);
  const [supplierFromURL, setSupplierFromURL] = useState('');

  const isMobile = useMediaQuery({ maxWidth: breakpoints.md - 1 });

  useEffect(() => {
    if (_user) {
      setStudentId(_user.student_id ?? null); // Set userId, or null if unavailable
      setTeamId(_user.team_id ?? null); // Set teamId, or null if unavailable
    }
  }, [_user]);

  const [partRequests, setPartRequests] = useState<PartRequest[]>([
    {
      status: 'requested',
      quantity: 1,
      url: '',
      part_num: '',
      description: '',
      price: 0,
    },
  ]);

  const addPartRequest = () => {
    const addedPartRequest: PartRequest = {
      status: 'requested',
      quantity: 1,
      url: '',
      part_num: '',
      description: '',
      price: 0,
    };
    setPartRequests([...partRequests, addedPartRequest]);
  };

  const removePartRequest = (index: number) => {
    setPartRequests((prevPartRequests) =>
      prevPartRequests.filter((_, i) => i !== index)
    );
    setFormErrors([]);
  };

  const handleChange = (
    index: number,
    e: React.ChangeEvent<HTMLInputElement>
  ) => {
    const { name, value } = e.target;
    setPartRequests((prevPartRequests) =>
      prevPartRequests.map((partRequest, i) =>
        i === index ? { ...partRequest, [name]: value } : partRequest
      )
    );
  };

  const validateFields = () => {
    const newErrors: Partial<Record<keyof PartRequest, boolean>>[] =
      partRequests.map(() => ({}));

    partRequests.forEach((partRequest, index) => {
      const fieldErrors: Partial<Record<keyof PartRequest, boolean>> = {};

      if (!partRequest.description.trim()) {
        fieldErrors.description = true;
      }
      if (
        !partRequest.quantity ||
        isNaN(Number(partRequest.quantity)) ||
        Number(partRequest.quantity) <= 0
      ) {
        fieldErrors.quantity = true;
      }
      if (
        !partRequest.price ||
        isNaN(Number(partRequest.price)) ||
        Number(partRequest.price) <= 0
      ) {
        fieldErrors.price = true;
      }

      let url = partRequest.url.trim();
      if (/^[a-zA-Z]+:\/\//.test(url) == false) {
        url = 'http://' + url;
      }

      if (!url || !isUrlHttp(url)) {
        fieldErrors.url = true;
      } else {
        setSupplierFromURL(extractSupplier(url));
      }

      if (Object.keys(fieldErrors).length > 0) {
        newErrors[index] = fieldErrors; // Store errors for the specific item
      }
    });

    setFormErrors(newErrors);
    return newErrors.every((errors) => Object.keys(errors).length === 0);
  };

  const clearFieldError = (index: number, field: keyof PartRequest) => {
    setFormErrors((prevErrors) => {
      const newErrors = [...prevErrors];
      if (newErrors[index]) {
        delete newErrors[index][field]; // Remove only the specific field error
        if (Object.keys(newErrors[index]).length === 0) {
          newErrors[index] = {}; // Keep an empty object to prevent undefined issues
        }
      }
      return newErrors;
    });
  };

  const autofillFromUrl = async (index: number, partRequest: PartRequest) => {
    let part;
    try {
      if (partRequest.url) {
        part = await getParts(undefined, partRequest.url);
      } else {
        return;
      }
    } catch (error) {
      console.error('Error fetching part:', error);
    }

    if (Array.isArray(part) && part.length > 0) {
      const fetchedPart = part[0];
      setPartRequests((prevPartRequests) => {
        const updatedPartRequests = [...prevPartRequests]; // Copy the existing array
        updatedPartRequests[index] = {
          ...updatedPartRequests[index], // Copy the old partRequest at that index
          part_num: fetchedPart.part_num,
          description: fetchedPart.description,
          price: fetchedPart.price,
          part_id: fetchedPart.part_id,
          supplier_id: fetchedPart.supplier_id,
        };
        return updatedPartRequests;
      });
    }
  };

  const handleSubmit = () => {
    if (validateFields()) {
      setIsConfirming(true);
      setShowReviewRequestModal(true);
    } else {
      // alert('Invalid input (temporary placeholder)');
    }
  };

  const [showReviewRequestModal, setShowReviewRequestModal] = useState(false);

  const hideReviewRequestModal = () => {
    setShowReviewRequestModal(false);
    setIsConfirming(false);
  };

  const extractSupplier = (url: string) => {
    if (/^[a-zA-Z]+:\/\//.test(url) == false) {
      url = 'http://' + url;
    }

    const supplierUrl = parse(new URL(url).hostname);
    return supplierUrl.domainWithoutSuffix as string;
  };

  const { addToast } = useToast();
  const handleConfirmSubmit = async (e: React.FormEvent) => {
    e.preventDefault(); // prevents re-render and refresh

    let partPrice: number | undefined = undefined;

    try {
      for (const partRequest of partRequests) {
        if (
          partRequest.part_id == undefined ||
          partRequest.supplier_id == undefined
        ) {
          const resultPart = await createNewPart(partRequest);

          if (
            resultPart &&
            'part_id' in resultPart &&
            'supplier_id' in resultPart
          ) {
            partRequest.part_id = resultPart.part_id;
            partRequest.supplier_id = resultPart.supplier_id;
            partPrice = resultPart.price;
          }

          if (!partRequest.part_id || !partRequest.supplier_id) {
            //console.error('Error creating part:', resultPart);
            return;
          }
        }

        if (!partPrice) {
          const resultPart = await getPart(partRequest.part_id);
          partPrice = resultPart.price;
        }

        const newRequest: Request = {
          student_id: Number(studentId),
          team_id: Number(teamId),
          part_id: partRequest.part_id,
          supplier_id: partRequest.supplier_id,
          status: 'requested',
          quantity: partRequest.quantity,
          subtotal: partPrice * partRequest.quantity,
        };
        const resultRequest = await createRequest(newRequest);

        if (resultRequest && resultRequest.request_id) {
          const team = await getTeam(Number(teamId));
          let url = partRequest.url;
          if (/^[a-zA-Z]+:\/\//.test(url) == false) {
            url = 'http://' + url;
          }
          let supplier = extractSupplier(url);

          const generated_message = 'New Request Created';
          const free_text = `Request #${resultRequest.request_id} for supplier "${supplier}" has been created by ${user?.first_name} ${user?.last_name} for ${getFormattedTeamName(team)}.`;
          const newNotification: Notification = {
            request_id: resultRequest.request_id,
            team_id: Number(teamId),
            generated_message: generated_message,
            free_text: free_text,
            for_instructor: user?.type == 'student' ? true : false,
          };
          await createNotification(newNotification);
        } else {
          // error
        }
      }

      addToast(
        'Your request' +
          (partRequests.length > 1 ? 's were' : ' was') +
          ' submitted.',
        'success'
      );

      setPartRequests([
        {
          status: 'requested',
          quantity: 1,
          url: '',
          part_num: '',
          description: '',
          price: 0,
        },
      ]);
    } catch {
      addToast('Request submission failed.', 'danger');
    }

    setIsConfirming(false);
    hideReviewRequestModal();
    onRequestSubmit();
  };

  const handleCancelSubmit = () => {
    setIsConfirming(false);
    hideReviewRequestModal();
  };

  return (
    <>
      <Modal show={showReviewRequestModal} onHide={hideReviewRequestModal}>
        <Modal.Header closeButton>
          <Modal.Title>Review Request Details</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className='mb-3'>
            Please confirm the details of your request before submitting. Once
            submitted, a request's part information cannot be changed.
          </div>
          <div style={{ overflowX: 'auto' }}>
            <Table bordered size='sm' responsive className='mb-2'>
              <thead className='text-end'>
                <tr>
                  <th style={{ whiteSpace: 'nowrap' }}>Item Description</th>
                  <th style={{ whiteSpace: 'nowrap' }}>Part #</th>
                  <th style={{ whiteSpace: 'nowrap' }}>Quantity</th>
                  <th style={{ whiteSpace: 'nowrap' }}>Unit Price ($)</th>
                </tr>
              </thead>
              <tbody>
                {partRequests.map((partRequest) => (
                  <tr className='text-end'>
                    <td>
                      {partRequest.description.substring(0, 30) +
                        (partRequest.description.length > 30 ? '...' : '')}
                    </td>
                    <td>
                      {partRequest.part_num ? partRequest.part_num : 'N/A'}
                    </td>
                    <td>{partRequest.quantity}</td>
                    <td>{Number(partRequest.price).toFixed(2)}</td>
                  </tr>
                ))}
              </tbody>
            </Table>
          </div>
        </Modal.Body>
        <Modal.Footer>
          <Button variant='secondary' onClick={handleCancelSubmit}>
            Cancel
          </Button>
          <Button variant='primary' onClick={handleConfirmSubmit}>
            Confirm Request
          </Button>
        </Modal.Footer>
      </Modal>

      <Form
        onSubmit={(event) => {
          event.preventDefault();
          handleSubmit();
        }}
        noValidate
      >
        {partRequests.map((partRequest, index) => (
          <div key={index} className='card mb-3'>
            <div className='card-header'>
              <div className='d-flex justify-content-between align-items-center'>
                <div>Part #{index + 1}</div>
                <Button
                  variant='danger'
                  onClick={() => removePartRequest(index)}
                  disabled={
                    isConfirming ||
                    (!studentId && !teamId) ||
                    partRequests.length <= 1
                  }
                >
                  <div className='d-flex align-items-top py-1'>
                    <Icon iconName='Trash' />
                  </div>
                </Button>
              </div>
            </div>
            <div className='card-body'>
              <div className='row'>
                <div className='col-md-9 mb-2'>
                  <label className='block text-sm font-medium label-style mb-1'>
                    URL: <span className='text-danger'>*</span>
                  </label>
                  <InputGroup hasValidation>
                    <Form.Control
                      type='text'
                      name='url'
                      placeholder='URL...'
                      value={partRequest.url}
                      onChange={(e) => {
                        // @ts-ignore
                        handleChange(index, e);
                        clearFieldError(index, 'url');
                      }}
                      onBlur={() => {
                        let url = partRequest.url.trim();
                        if (/^[a-zA-Z]+:\/\//.test(url) == false) {
                          url = 'http://' + url;
                        }

                        if (isUrlHttp(url)) {
                          autofillFromUrl(index, partRequest); // Function called when leaving the field
                        }
                      }}
                      className={`${formErrors[index]?.url ? 'is-invalid' : ''}`}
                      required
                      disabled={isConfirming || (!studentId && !teamId)}
                    />
                    <Form.Control.Feedback type='invalid'>
                      Please enter a valid URL.
                    </Form.Control.Feedback>
                  </InputGroup>
                </div>
                <div className='col-md-3 mb-2'>
                  <label className='block text-sm font-medium label-style mb-1'>
                    Part number:
                  </label>
                  <InputGroup hasValidation>
                    <Form.Control
                      type='text'
                      name='part_num'
                      placeholder='Part number...'
                      value={partRequest.part_num}
                      onChange={(e) => {
                        // @ts-ignore
                        handleChange(index, e);
                        clearFieldError(index, 'part_num');
                        if (
                          partRequest.part_num !== '' &&
                          formErrors[index]?.url
                        ) {
                          e.target.setCustomValidity('test');
                        }
                      }}
                      className={`${partRequest.part_num !== '' && formErrors[index]?.url ? 'is-invalid' : ''}`}
                      disabled={isConfirming || (!studentId && !teamId)}
                    />
                    <Form.Control.Feedback type='invalid'>
                      A valid URL must be entered first.
                    </Form.Control.Feedback>
                  </InputGroup>
                </div>
              </div>
              <div className='row'>
                <div className='col-md-6 mb-2'>
                  <label className='block text-sm font-medium label-style mb-1'>
                    Item description: <span className='text-danger'>*</span>
                  </label>
                  <InputGroup hasValidation>
                    <Form.Control
                      type='text'
                      name='description'
                      placeholder='Item description...'
                      value={partRequest.description}
                      onChange={(e) => {
                        // @ts-ignore
                        handleChange(index, e);
                        clearFieldError(index, 'description');
                      }}
                      className={`${formErrors[index]?.description ? 'is-invalid' : ''}`}
                      required
                      disabled={isConfirming || (!studentId && !teamId)}
                    />
                    <Form.Control.Feedback type='invalid'>
                      Please enter a description.
                    </Form.Control.Feedback>
                  </InputGroup>
                </div>
                <div className='col-md-3 mb-2'>
                  <label className='block text-sm font-medium label-style mb-1'>
                    Quantity: <span className='text-danger'>*</span>
                  </label>
                  <InputGroup hasValidation>
                    <Form.Control
                      type='number'
                      name='quantity'
                      min={1}
                      placeholder='Quantity...'
                      defaultValue={1}
                      onChange={(e) => {
                        // @ts-ignore
                        handleChange(index, e);
                        clearFieldError(index, 'quantity');
                      }}
                      className={`${formErrors[index]?.quantity ? 'is-invalid' : ''}`}
                      required
                      disabled={isConfirming || (!studentId && !teamId)}
                    />
                    <Form.Control.Feedback type='invalid'>
                      Please enter a positive, non-zero quantity.
                    </Form.Control.Feedback>
                  </InputGroup>
                </div>
                <div className='col-md-3'>
                  <label className='block text-sm font-medium label-style mb-1'>
                    Unit price: <span className='text-danger'>*</span>
                  </label>
                  <InputGroup>
                    <InputGroup.Text>$</InputGroup.Text>
                    <Form.Control
                      type='number'
                      name='price'
                      step='0.01'
                      min='0.01'
                      placeholder='Unit price...'
                      value={partRequest.price || ''}
                      onChange={(e) => {
                        // @ts-ignore
                        handleChange(index, e);
                        clearFieldError(index, 'price');
                      }}
                      className={`${formErrors[index]?.price ? 'is-invalid' : ''}`}
                      required
                      disabled={isConfirming || (!studentId && !teamId)}
                    />
                    <Form.Control.Feedback type='invalid'>
                      Please enter a positive, non-zero price.
                    </Form.Control.Feedback>
                  </InputGroup>
                </div>
              </div>
            </div>
          </div>
        ))}
        <div className='row g-3'>
          <div className='col-md-6'>
            <Button
              variant='primary'
              type='button'
              onClick={addPartRequest}
              className={`${isMobile ? 'w-100' : ''}`}
              disabled={isConfirming || (!studentId && !teamId)}
            >
              <div className='d-flex justify-content-center align-items-center'>
                <Icon iconName='PlusLg' />
                <span className='ms-1'>Add Part</span>
              </div>
            </Button>
          </div>
          <div className='col-md-6'>
            <Button
              variant='success'
              type='submit'
              className={`${isMobile ? 'w-100' : 'float-end'}`}
              disabled={isConfirming || (!studentId && !teamId)}
            >
              Submit Request
            </Button>
          </div>
        </div>
      </Form>
    </>
  );
}
