import React, { useState } from 'react';
import styled from 'styled-components';
import CalendarButton from './CalendarButton'; // CalendarButton 컴포넌트 import

const CalendarContainer = styled.div`
    margin-top: 40px;
`;

const CalendarNavigation = styled.div`
    display: flex;
    justify-content: space-between;
    padding: 0 10px;
`;

const NavButton = styled.button`
    background-color: transparent;
    border: none;
    color: #000000;
    font-size: 26px;
    cursor: pointer;

    &:hover {
        color: #007bff;
    }
`;

const MonthYearTitle = styled.span`
    font-size: 26px;
    font-weight: bold;
`;

const WeekdaysRow = styled.div`
    display: flex;
    justify-content: space-around;
    text-align: center;
    font-weight: medium;
    color: #2f2f2f;
    margin-top: 25px;
    margin-bottom: 10px;
`;

interface WeekdayCellProps {
    isSunday?: boolean;
    isSaturday?: boolean;
}

const WeekdayCell = styled.div<WeekdayCellProps>`
    width: 14.28%;
    color: ${(props: WeekdayCellProps): string => {
        return props.isSunday
            ? '#ff4343'
            : props.isSaturday
              ? '#0085ff'
              : '#2f2f2f';
    }};

    abbr {
        text-decoration: none;
    }
`;

const DaysGrid = styled.div`
    display: flex;
    flex-direction: column;
`;

const WeekRow = styled.div`
    display: flex;
    width: 100%;
`;

interface DayCellProps {
    isCurrentMonth: boolean;
    hasEvent?: boolean;
    isSelected?: boolean;
}

const DayCell = styled.div<DayCellProps>`
    flex: 1;
    padding: 15px 15px;
    font-size: 18px;
    background-color: ${(props: DayCellProps): string => {
        if (props.isSelected) {
            return '#40A3FF'; // 선택된 날짜 배경색
        }
        if (props.hasEvent) {
            return '#e0f0ff'; // 일정 있는 날 배경색
        }
        return '#ececec'; // 기본 배경색
    }};
    border-radius: 13px;
    text-align: center;
    margin: 10px 5px;
    cursor: pointer;
    color: ${(props: DayCellProps): string => {
        if (props.isSelected) {
            return '#ffffff'; // 선택된 날짜의 텍스트 색상
        }
        return props.isCurrentMonth ? '#000' : '#aaa';
    }};

    &:hover {
        background-color: ${(props: DayCellProps): string => {
            return props.isSelected ? '#40A3FF' : '#d4e5f6'; // hover 시 색상 유지
        }};
    }

    position: relative;
`;

const EventDot = styled.div`
    width: 6px;
    height: 6px;
    background-color: #40a3ff;
    border-radius: 50%;
    position: absolute;
    bottom: 5px;
    left: 50%;
    transform: translateX(-50%);
`;

const ScheduleButtonContainer = styled.div`
    display: flex;
    justify-content: flex-end;
    margin-top: 20px;
`;

const ProjectCalendar: React.FC = () => {
    const today: Date = new Date();
    const [currentDate, setCurrentDate] = useState<Date>(new Date());
    const [isSelectingDates, setIsSelectingDates] = useState<boolean>(false);
    const [selectedStartDate, setSelectedStartDate] = useState<Date | null>(
        null,
    );
    const [selectedEndDate, setSelectedEndDate] = useState<Date | null>(null);

    // 일정이 있는 날짜 목록
    const eventDates: Date[] = [
        new Date(2024, 9, 14), // 2024년 10월 14일에 일정
        new Date(2024, 9, 20), // 2024년 10월 20일에 일정
        // 추가 일정...
    ];

    // 월과 연도를 가져오는 함수
    const getMonthYear = (date: Date): string => {
        return date.toLocaleString('ko-KR', { year: 'numeric', month: 'long' });
    };

    // 이전 달로 이동하는 함수
    const prevMonth = (): void => {
        setCurrentDate(
            new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1),
        );
    };

    // 다음 달로 이동하는 함수
    const nextMonth = (): void => {
        setCurrentDate(
            new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1),
        );
    };

    // 요일 배열을 반환하는 함수
    const getWeekdays = (): string[] => {
        return ['일', '월', '화', '수', '목', '금', '토'];
    };

    // 달력을 생성하는 함수
    const generateCalendar = (): Date[][] => {
        const startOfMonth: Date = new Date(
            currentDate.getFullYear(),
            currentDate.getMonth(),
            1,
        );
        const endOfMonth: Date = new Date(
            currentDate.getFullYear(),
            currentDate.getMonth() + 1,
            0,
        );

        const dates: Date[][] = [];
        const current: Date = new Date(startOfMonth);
        current.setDate(current.getDate() - current.getDay());

        while (current <= endOfMonth || current.getDay() !== 0) {
            const week: Date[] = [];

            for (let i = 0; i < 7; i += 1) {
                week.push(new Date(current));
                current.setDate(current.getDate() + 1);
            }

            dates.push(week);
        }

        return dates;
    };

    // 두 날짜가 같은 날인지 확인하는 함수
    const isSameDay = (date1: Date, date2: Date): boolean => {
        return (
            date1.getFullYear() === date2.getFullYear() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getDate() === date2.getDate()
        );
    };

    // 날짜가 두 날짜 사이에 있는지 확인하는 함수
    const isBetweenDates = (
        date: Date,
        startDate: Date,
        endDate: Date,
    ): boolean => {
        const time = date.getTime();
        const startTime = startDate.getTime();
        const endTime = endDate.getTime();

        return time >= startTime && time <= endTime;
    };

    // 날짜 클릭 이벤트 처리 함수
    const handleDateClick = (date: Date): void => {
        if (isSelectingDates) {
            if (!selectedStartDate) {
                setSelectedStartDate(date);
            } else if (!selectedEndDate) {
                if (date >= selectedStartDate) {
                    setSelectedEndDate(date);
                } else {
                    setSelectedEndDate(selectedStartDate);
                    setSelectedStartDate(date);
                }
            } else {ㅋ
                // 이미 두 날짜가 선택된 경우, 선택 초기화하고 새로 시작
                setSelectedStartDate(date);
                setSelectedEndDate(null);
            }
        } else {
            console.log(date);
        }
    };

    // 날짜가 선택되었는지 확인하는 함수
    const isSelected = (date: Date): boolean => {
        if (selectedStartDate && selectedEndDate) {
            return isBetweenDates(date, selectedStartDate, selectedEndDate);
        } else if (selectedStartDate) {
            return isSameDay(selectedStartDate, date);
        }
        return false;
    };

    const dates: Date[][] = generateCalendar();

    return (
        <CalendarContainer>
            <CalendarNavigation>
                <NavButton type="button" onClick={prevMonth}>
                    &lt;
                </NavButton>
                <MonthYearTitle>{getMonthYear(currentDate)}</MonthYearTitle>
                <NavButton type="button" onClick={nextMonth}>
                    &gt;
                </NavButton>
            </CalendarNavigation>
            <WeekdaysRow>
                {getWeekdays().map(
                    (day: string, index: number): JSX.Element => (
                        <WeekdayCell
                            key={day}
                            isSunday={index === 0}
                            isSaturday={index === 6}
                        >
                            <abbr title={day}>{day}</abbr>
                        </WeekdayCell>
                    ),
                )}
            </WeekdaysRow>
            <DaysGrid>
                {dates.map(
                    (week: Date[]): JSX.Element => (
                        <WeekRow key={week[0].toISOString()}>
                            {week.map((date: Date): JSX.Element => {
                                const isCurrentMonth: boolean =
                                    date.getMonth() === currentDate.getMonth();

                                // 일정이 있는 날짜인지 확인
                                const hasEvent: boolean = eventDates.some(
                                    (eventDate: Date): boolean =>
                                        isSameDay(eventDate, date),
                                );

                                return (
                                    <DayCell
                                        key={date.toISOString()}
                                        isCurrentMonth={isCurrentMonth}
                                        hasEvent={hasEvent}
                                        isSelected={isSelected(date)}
                                        onClick={() => {
                                            handleDateClick(date);
                                        }}
                                    >
                                        {date.getDate()}
                                        {hasEvent && <EventDot />}
                                    </DayCell>
                                );
                            })}
                        </WeekRow>
                    ),
                )}
            </DaysGrid>
            <ScheduleButtonContainer>
                <CalendarButton
                    isSelectingDates={isSelectingDates}
                    hasSelectedDates={!!selectedStartDate}
                    onClick={() => {
                        if (isSelectingDates) {
                            if (selectedStartDate) {
                                console.log(
                                    '선택된 시작 날짜:',
                                    selectedStartDate,
                                );
                                if (selectedEndDate) {
                                    console.log(
                                        '선택된 종료 날짜:',
                                        selectedEndDate,
                                    );
                                } else {
                                    console.log(
                                        '종료 날짜는 선택되지 않았습니다.',
                                    );
                                }
                                // 여기서 일정 추가 로직을 구현하세요.

                                // 선택 초기화
                                setIsSelectingDates(false);
                                setSelectedStartDate(null);
                                setSelectedEndDate(null);
                            } else {
                                console.log('날짜를 선택하세요.');
                            }
                        } else {
                            setIsSelectingDates(true);
                            setSelectedStartDate(null);
                            setSelectedEndDate(null);
                            console.log('회의 일정잡기 버튼 클릭');
                        }
                    }}
                    onCancel={() => {
                        setIsSelectingDates(false);
                        setSelectedStartDate(null);
                        setSelectedEndDate(null);
                        console.log('취소 버튼 클릭');
                    }}
                />
            </ScheduleButtonContainer>
        </CalendarContainer>
    );
};

export default ProjectCalendar;

✏️ 소감

이번 ProjectCalendar 컴포넌트 개발을 통해 일정 선택 및 달력 UI의 기본 구조를 구현할 수 있었는데, 특히 스타일링과 이벤트 로직을 다루는 부분에서 많은 것을 배울 수 있었습니다. 이 컴포넌트는 사용자가 시작 및 종료 날짜를 선택하여 일정 구간을 설정하는 기능을 제공하며, 일정이 있는 날짜는 별도의 표시로 시각화할 수 있도록 설정했습니다.

가장 큰 도전이었던 부분은 두 날짜를 선택하는 과정에서 조건별로 상태를 관리하는 로직이었고, 이를 통해 React의 상태 관리와 조건문 활용에 대해 깊이 이해하게 되었습니다. 또한, styled-components를 이용해 주말과 평일, 선택된 날짜에 따라 색상을 달리 적용하는 등 세밀한 스타일링을 추가하며, 다양한 상황에 맞춰 UI를 다듬는 경험을 할 수 있었습니다.

향후 이 컴포넌트에 Drag로 날짜 구간을 선택하는 기능이나 일정 데이터를 서버와 연동하는 기능을 추가해보고 싶습니다. 이번 작업을 통해 컴포넌트를 보다 확장성 있게 설계하는 방법을 고민할 수 있었고, React와 TypeScript 조합의 장점을 느낀 시간이었습니다.