import 'bootstrap-icons/font/bootstrap-icons.css';
import '../style.css';

import { Accordion, Button, ButtonGroup, Card, Col, Form, ListGroup } from 'react-bootstrap';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import API from '../API';
import dayjs from 'dayjs';

//Can't get it from database because it is not saved.
//This number is used only for triggering the re-render of the content of the Forms of each block showed at video. (ex when handleUp or handleDown)
function generatelocalId() {
    return Math.random().toString(36).substring(2) + Date.now().toString(36);
}

function BlockList(props) {

    function headerBlock() {
        this.blockType = "Header";
        this.content = "";
    }

    function paragraphBlock() {
        this.blockType = "Paragraph";
        this.content = "";
    }
    function imageBlock() {
        this.blockType = "Image";
        this.content = "";
    }

    const addToList = (x) => {
        props.setList((oldList) => [...oldList, x]);
    };

    return (
        <>
            <h5 style={{ textAlign: "center" }}>Components</h5>
            <p></p>
            <Card>
                <ListGroup>
                    <ListGroup.Item >
                        Header
                        <Button className="float-end addbutton" variant="outline-success"
                            onClick={() => {
                                addToList(new headerBlock());
                            }}>
                            <i className="bi bi-plus"></i>
                        </Button>
                    </ListGroup.Item>
                    <ListGroup.Item >
                        Paragraph
                        <Button className="float-end addbutton" variant="outline-success"
                            onClick={() => {
                                addToList(new paragraphBlock());
                            }}>
                            <i className="bi bi-plus"></i>
                        </Button>
                    </ListGroup.Item>
                    <ListGroup.Item >
                        Image
                        <Button className="float-end addbutton" variant="outline-success"
                            onClick={() => {
                                addToList(new imageBlock());
                            }}>
                            <i className="bi bi-plus"></i>
                        </Button>
                    </ListGroup.Item>
                </ListGroup>
            </Card>
        </>
    );
}

function CreatePageBody(props) {

    return (
        <Accordion>
            {props.list.map((x) => <MyBlock x={x} key={generatelocalId()} list={props.list} setList={props.setList} images={props.images} />)}
        </Accordion>
    );
}

function MyBlock(props) {

    const x = props.x;
    const images = props.images;
    const [content, setContent] = useState(x.content);
    const [notAligned, setNotAligned] = useState(false);

    const removeFromList = (x) => {
        props.setList((oldlist) => oldlist.filter((item) => item != x));
    };

    const handleUp = (x) => {
        props.setList(oldList => {
            const index = oldList.indexOf(x);
            const newList = [...oldList];
            [newList[index - 1], newList[index]] = [newList[index], newList[index - 1]];
            return newList;
        });
    };

    const handleDown = (x) => {
        props.setList(oldList => {
            const index = oldList.indexOf(x);
            const newList = [...oldList];
            [newList[index], newList[index + 1]] = [newList[index + 1], newList[index]];
            return newList;
        });
    };


    const handleContentChange = (x) => {
        props.setList((oldList) => {
            const newList = oldList.map((item) => (item === x ? { ...item, content: content } : item));
            return newList;
        })
    };

    useEffect(() => { 
        if(notAligned){
        handleContentChange(x);
        setNotAligned(false);
    }
    }, [notAligned]);


    return (
        <Accordion.Item eventKey={props.list.indexOf(x)}>
            <Accordion.Header >
                <div className="accordion-style">
                    {x.blockType}
                    <ButtonGroup style={{ paddingRight: "2%" }} >
                        {props.list.indexOf(x) != 0 && ( //button as div avoid nested buttons error validateDOMnesting - since accordion header is a button itself!
                            <Button as='div' style={{ fontSize: "0.8rem", padding: "0.25rem 0.5rem" }} variant="outline-secondary"
                                onClick={(ev) => { ev.stopPropagation(); handleUp(x) }}>
                                <i className="bi bi-arrow-up"></i>
                            </Button>)}
                        {props.list.indexOf(x) != (props.list.length - 1) && (
                            <Button as='div' style={{ fontSize: "0.8rem", padding: "0.25rem 0.5rem" }} variant="outline-secondary"
                                onClick={(ev) => { ev.stopPropagation(); handleDown(x) }}>
                                <i className="bi bi-arrow-down"></i>
                            </Button>)}
                        <Button as='div' size="sm" variant="outline-danger"
                            onClick={(ev) => { ev.stopPropagation(); removeFromList(x) }}>
                            <i className="bi bi-x-lg"></i>
                        </Button>
                    </ButtonGroup>
                </div>
            </Accordion.Header>
            <Accordion.Body>
                {x.blockType != "Image" ? (
                    <Form.Control as="textarea" value={content} onChange={(ev) => { setContent(ev.target.value); setNotAligned(true); }} ></Form.Control>
                ) : (
                    <div>
                        {images.map((image) => (
                            <label key={generatelocalId()} style={{ paddingRight: "20px" }}>
                                <input value={image.url} onChange={(ev) => { setContent(ev.target.value); setNotAligned(true); }} checked={content == image.url} type="radio" />
                                <img className="img-box" src={image.url} alt={image.alt} />
                            </label>
                        ))}
                    </div>
                )}
            </Accordion.Body>
        </Accordion.Item>
    );

}



function ActionList(props) {

    // Placed here because otherwise handleAction couldn't call navigate.
    // Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
    const navigate = useNavigate();

    const [date, setDate] = useState(""); // Used to publish programmed pages

    const list = props.list;
    const title = props.title;

    return (
        <Col className="pt-4">
            <Button variant="warning" style={{ marginBottom: "2%", width: "100%" }} onClick={() => handleAction("draft")}>Save as Draft</Button>
            <Button variant="success" style={{ marginBottom: "10%", width: "100%" }} onClick={() => handleAction("publish")}>Publish</Button>
            <Form.Control type="date" name="date" value={date} onChange={(ev) => setDate(ev.target.value)} />
            <Button variant="secondary" style={{ marginTop: "2%", width: "100%" }} onClick={() => handleAction("programmed")}>Schedule Publication</Button>
        </Col>
    );

    function handleAction(action) {

        let valid = true;
        let data = {};

        if (title.trim() == "") {
            valid = false;
            props.handleError("You have to choose a title for the page.");
        }
        else if (!(list.some(item => item.blockType == 'Header')) ||
            (!(list.some(item => item.blockType == 'Paragraph') || list.some(item => item.blockType == 'Image')))
        ) {
            valid = false;
            props.handleError("You have to insert at least a Header and a Paragraph/Image.");
        }
        else if (list.some(item => (item.content.trim() == ""))) {
            valid = false;
            props.handleError("At least one block without content!");
        }

        if (valid) {
            data = { // Data formatted. Ready to send it to the server for Page Creation.
                title: title,
                blocks: JSON.stringify(list) // Saved directly as json in db
            };

            switch (action) {
                case "draft":
                    Object.assign(data, { publishDate: null });
                    break;
                case "publish":
                    Object.assign(data, { publishDate: dayjs().format("YYYY-MM-DD") });
                    break;
                case "programmed":
                    const Date = dayjs(date);
                    if (!Date.isValid() || Date.isBefore(dayjs())) { //dayjs() returns today date
                        props.handleError("Select a valid date.");
                        return;
                    }
                    Object.assign(data, { publishDate: Date.format("YYYY-MM-DD") });
                    break;
                default:
                    break;

            }

            API.createPage(data)
                .then(() => {
                    navigate("/backoffice")
                })
                .catch((err) => props.handleError(err));
        }
    }

}




function Title(props) {
    return (
        <Form.Control type="text" name="text" autoFocus value={props.title} placeholder="Page Title" onChange={ev => props.setTitle(ev.target.value)} />
    );
}

export { Title, ActionList, BlockList, CreatePageBody, MyBlock };



The use of setNotAligned(true) makes me stop writing inside the form. I want to be able to keep writing how much I want