import React, { type ChangeEventHandler, useContext } from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import {
    Col,
    Form,
    InputGroup,
    Row,
    MarketSelector,
    getContinents,
} from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import { ServiceMultiSelect } from 'src/components/shared/service-multiselect';
import { TransactionTypeMultiSelect } from 'src/components/shared/transaction-type-multiselect';
import {
    DELETE_TERM_CONDITION,
    SET_CONTRACT_TERM_CONDITION,
} from 'src/constants';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import type { AbacusDistroContractTermCondition } from 'src/types/abacus-contract-term';

export interface ContractTermConditionFormProps {
    condition: AbacusDistroContractTermCondition;
    dragAndDropCondition: (dragIndex: number, dropIndex: number) => void;
    index: number;
    isDraggable?: boolean;
    portalElement?: HTMLElement;
    showActionColumn?: boolean;
    // Opt-in: highlight the Label's share input red when its value is present
    // but outside the valid 0-100 range. Off by default so existing callers
    // are unaffected.
    highlightInvalidRate?: boolean;
}

export default function ContractTermConditionForm({
    condition,
    index,
    isDraggable,
    portalElement,
    showActionColumn = false,
    highlightInvalidRate = false,
}: ContractTermConditionFormProps) {
    const { state, dispatch } = useContext(ContractTermContext);
    const onDelete = (
        termCondition: AbacusDistroContractTermCondition,
        termConditionIndex?: number
    ) =>
        dispatch({
            type: DELETE_TERM_CONDITION,
            termCondition,
            termConditionIndex,
        });

    const {
        attributes,
        listeners,
        setNodeRef,
        transform,
        transition,
        isDragging,
    } = useSortable({ id: condition.priority });

    const style = isDraggable
        ? { transform: CSS.Transform.toString(transform), transition }
        : undefined;

    const changeHandler: ChangeEventHandler<HTMLInputElement> = e => {
        const {
            target: { name, value },
        } = e;

        if (['countries', 'stores', 'transactionTypes'].includes(name)) {
            const newValue = value || [];
            return dispatch({
                type: SET_CONTRACT_TERM_CONDITION,
                index,
                name,
                value: newValue,
            });
        }

        return dispatch({
            type: SET_CONTRACT_TERM_CONDITION,
            index,
            name,
            value,
        });
    };

    const existingConditions = state.conditions.filter(
        (termCondition: any) => termCondition.contractTermConditionId !== null
    );
    const isDeleteDisabled =
        existingConditions.length === 1 &&
        existingConditions[0].contractTermConditionId ===
            condition.contractTermConditionId;
    // In the Action-column layout the trash always shows, disabled when it's
    // the only row (you can't remove the last condition).
    const actionDeleteDisabled =
        isDeleteDisabled || state.conditions.length === 1;
    const termRate =
        // @ts-expect-error: termRate can be string | null, need to validate if it's a valid number
        !isNaN(condition.termRate) || condition.termRate === '.'
            ? (condition.termRate ?? undefined)
            : '';

    const rateNumber = parseFloat(String(condition.termRate ?? ''));
    const rateInvalid =
        highlightInvalidRate &&
        condition.termRate != null &&
        String(condition.termRate) !== '' &&
        !Number.isNaN(rateNumber) &&
        (rateNumber < 0 || rateNumber > 100);

    return (
        <Row
            className={`ContractTermsConditionsTable-row ${
                isDragging ? 'isDragging' : ''
            }`}
            id={`condition-${condition.priority}`}
            key={`contract-term-condition-row-${condition.priority}`}
            ref={isDraggable ? setNodeRef : undefined}
            style={style}
            data-testid="contractTermConditionRow"
            {...(isDraggable ? attributes : {})}
            {...(isDraggable ? listeners : {})}
        >
            <Col
                sm="1"
                className={`priorityControl ${isDraggable ? 'draggable' : ''}`}
                data-testid="contractTermConditionDragIcon"
            >
                {isDraggable && <GlyphIcon name="drag" size={16} />}
                {condition.priority}
            </Col>
            <Col sm="3">
                <TransactionTypeMultiSelect
                    className="transactionType"
                    onChange={e =>
                        changeHandler({
                            // @ts-expect-error: missing some properties on event target but we don't need them
                            target: {
                                name: 'transactionTypes',
                                value:
                                    e &&
                                    e.map(
                                        ({ value }: { value: string }) => value
                                    ),
                            },
                        })
                    }
                    placeholder="All"
                    portalElement={portalElement}
                    selectedValue={condition.conditions.transactionTypes}
                    transactionTypes={state.transactionTypes}
                    transactionTypeGroups={state.transactionTypeGroups}
                />
            </Col>
            <Col sm="3">
                <ServiceMultiSelect
                    className="contractTermConditionService"
                    services={state.stores}
                    onChange={e =>
                        changeHandler({
                            // @ts-expect-error: missing some properties on event target but we don't need them
                            target: {
                                name: 'stores',
                                value:
                                    e &&
                                    e.map(
                                        ({ value }: { value: string }) => value
                                    ),
                            },
                        })
                    }
                    placeholder="All"
                    portalElement={portalElement}
                    selectedValue={condition.conditions.stores}
                />
            </Col>
            <Col sm={showActionColumn ? '2' : '3'}>
                <MarketSelector
                    className="contractTermConditionCountry"
                    id="countries"
                    quickSelections={[...getContinents()]}
                    onChange={e =>
                        changeHandler({
                            target: {
                                name: 'countries',
                                // @ts-expect-error: EventTarget wants a value as a string but we use an array here
                                value: e?.map(c => c.alpha3),
                            },
                        })
                    }
                    name="countries"
                    placeholder="All"
                    selectedValue={condition.conditions.countries}
                    requireApply={false}
                    portalElement={portalElement}
                />
            </Col>
            {showActionColumn ? (
                <>
                    <Col sm="2">
                        <InputGroup>
                            <Form.Control
                                data-testid="termRate"
                                type="number"
                                step="0.01"
                                value={termRate}
                                name="termRate"
                                onChange={changeHandler}
                                isInvalid={rateInvalid}
                            />
                            <InputGroup.Append>
                                <InputGroup.Text>%</InputGroup.Text>
                            </InputGroup.Append>
                        </InputGroup>
                    </Col>
                    <Col sm="1">
                        <div
                            className={cx({
                                deleteTermCondition: true,
                                disableDelete: actionDeleteDisabled,
                            })}
                            data-testid="contractTermConditionDeleteIcon"
                            onClick={() =>
                                !actionDeleteDisabled &&
                                onDelete(condition, index)
                            }
                        >
                            <GlyphIcon name="trash" size={16} />
                        </div>
                    </Col>
                </>
            ) : (
                <Col sm="2">
                    <InputGroup>
                        <Form.Control
                            data-testid="termRate"
                            type="number"
                            step="0.01"
                            value={termRate}
                            name="termRate"
                            onChange={changeHandler}
                            isInvalid={rateInvalid}
                        />
                        <InputGroup.Append>
                            <InputGroup.Text>%</InputGroup.Text>
                        </InputGroup.Append>
                    </InputGroup>
                    {state.conditions.length > 1 && (
                        <div
                            className={cx({
                                deleteTermCondition: true,
                                disableDelete: isDeleteDisabled,
                            })}
                            data-testid="contractTermConditionDeleteIcon"
                            onClick={() =>
                                !isDeleteDisabled && onDelete(condition, index)
                            }
                        >
                            <GlyphIcon name="trash" size={16} />
                        </div>
                    )}
                </Col>
            )}
        </Row>
    );
}
