import React, { useState, useEffect } from 'react';
import '../src/App.css';


// Spoiler
// Реализуйте компонент Spoiler, скрывающий контент и открывающий его по клику. Компонент будет получать 
// 3 пропс: header, который будет выводится всегда 
// open, может быть true или false, если написать в JSX без значения, это значит open={true}
// вложенный контент, т. е. children, который отображается в открытом состоянии спойлера и не отображается в закрытом. 
// Изначально компонент имеет состояние переданное через пропс open По клику на <div> в котором будет
// отображаться header должно меняться состояние на противоположное Обеспечьте условие, которое будет
// показывать или нет children.
const Spoiler = ({ header = "+", open, children }) => {
  const [isOpen, setOpen] = useState(open);
  return (
    <>
      <div onClick={() => setOpen(!isOpen)}>{header}</div>
      {isOpen && children}
    </>
  )
}

// RangeInput
// Реализовать компонент RangeInput, отображающий обычный <input /> со следующими возможностями:
// prop min - минимальная длина строки в инпуте, если меньше - инпут становится красным
// prop max - максимальная длина строки в инпуте, если большe - инпут становится красным
// Используйте компонент-класс и setState для отслеживания и валидации длины инпута. Или useState
const RangeInput = ({ min, max }) => {
  const [text, setText] = useState('');

  const textLengthCheck = text.length < min || text.length > max ? { border: "1px solid red" } : { border: "1px solid black" };

  return (
    <input
      onChange={e => setText(e.target.value)}
      value={text}
      style={textLengthCheck}
    />
  )
}

// LoginForm:
// принимает пропс-колбэк (функцию) onLogin;
// рисует форму логина (пару полей ввода и кнопка "Login")
// использует state (2 штуки) - для логина и пароля;
// не позволяет нажать на кнопку (disabled) пока логин/пароль отсутствуют (или можно добавить какие-то
// более параноидальные проверки на длину/набор символов;
// при нажатии на кнопку запускает onLogin и передает в него login и password из state;
const LoginForm = ({ onLogin }) => {
  const [login, setLogin] = useState('');
  const [password, setPassword] = useState('');

  const lengthCheck = !(login.length >= 4 && password.length >= 6);

  return (
    <div>
      <input
        value={login}
        type="text"
        placeholder="Login"
        onChange={e => setLogin(e.target.value)}
      />
      <input
        value={password}
        type="password"
        placeholder="Password"
        onChange={e => setPassword(e.target.value)}
      />
      <button
        onClick={() => onLogin({ login, password })}
        disabled={lengthCheck}
        type="submit">
        Login
      </button>
    </div>
  )
}

// PasswordConfirm
// Реализовать компонент PasswordConfirm, отображающий два <input type='password'/> со следующими
// возможностями:
// prop min - минимальная длина пароля
// Используйте компонент-класс и setState для отслеживания и валидации совпадения паролей и проверки
// на длину.Или useState
// По желанию добавьте более хитрые валидации типа проверки на размеры буков и наличие цифр в пароле.
const PasswordConfirm = ({ min }) => {
  const [password, setPassword] = useState('');
  const [passwordConfirm, setPasswordConfirm] = useState('');
  let passwordLengthCheck = password.length < min || passwordConfirm.length < min ?
    { border: "1px solid red" } : { border: "1px solid black" };
  let passwordMatch = password === passwordConfirm ?
    { color: "red", fontSize: '12px', display: 'none' } : { color: "red", fontSize: '12px', display: 'block' };
  return (
    <div>
      <input
        value={password}
        type="password"
        placeholder="Password"
        onChange={e => setPassword(e.target.value)}
        style={passwordLengthCheck}
      />
      <input
        value={passwordConfirm}
        type="password"
        placeholder="Password"
        onChange={e => setPasswordConfirm(e.target.value)}
        style={passwordLengthCheck}
      />
      <div style={passwordMatch}>Password mismatch</div>
    </div>
  )
}

// Timer
// Напишите компонент, в который передается через props количество секунд, а компонент при этом реализует
// обратный отсчет раз в секунду уменьшая количество секунд на 1. Останавливается на 0.
// Добавьте в компонент кнопку паузы. Компонент должен отображать часы, минуты и секунды.
const Timer = ({ sec }) => {
  const [allSeconds, setAllSeconds] = useState(sec);
  const [isRunning, setIsRunning] = useState(false);
  const getFullTime = () => {
    let hours = Math.floor(allSeconds / 3600) || 0;
    if (hours < 10 && hours >= 0) {
      hours = '0' + hours;
    }
    let minutes = Math.floor((allSeconds - hours * 3600) / 60) || 0;
    if (minutes < 10 && minutes >= 0) {
      minutes = '0' + minutes;
    }
    let seconds = allSeconds - hours * 3600 - minutes * 60 || 0;
    if (seconds < 10 && seconds >= 0) {
      seconds = '0' + seconds;
    }
    return hours + ':' + minutes + ':' + seconds;
  }

  // useEffect(() => {
  //   if (isRunning) {
  //     const timerId = setInterval(() => setAllSeconds(allSeconds => {
  //       if (allSeconds <= 0) {
  //         setIsRunning(false);
  //         return 0;
  //       }
  //       return allSeconds - 1;
  //     }), 1000);
  //     return () => clearInterval(timerId);
  //   }
  // }, [isRunning]);

  useEffect(() => {
    if (allSeconds === 0) {
      setIsRunning(false);
    }
  }, [allSeconds === 0]);

  useEffect(() => {
    if (isRunning) {
      const timerId = setInterval(() => setAllSeconds(allSeconds => allSeconds - 1), 1000);
      return () => clearInterval(timerId);
    }
  }, [isRunning]);

  return (
    <div>
      <h2>Timer</h2>
      <h4>{getFullTime()}</h4>
      <button onClick={() => setIsRunning(isRunning => !isRunning)}>{!isRunning ? "Start" : "Pause"}</button>
    </div>
  )
}

// TimerControl
// Напишите компонент, с тремя полями ввода (часы, минуты и секунды) и кнопкой Start, по которой будет
// стартовать компонент Timer
const TimerWithControl = ({ sec, isStart }) => {
  const [allSeconds, setAllSeconds] = useState(sec);
  const [start, setStart] = useState(isStart); // initialValue of useState is used only for the first render https://reactjs.org/docs/hooks-reference.html#usestate 
  const getFullTime = () => {
    let hours = Math.floor(allSeconds / 3600) || 0;
    if (hours < 10 && hours >= 0) {
      hours = '0' + hours;
    }
    let minutes = Math.floor((allSeconds - hours * 3600) / 60) || 0;
    if (minutes < 10 && minutes >= 0) {
      minutes = '0' + minutes;
    }
    let seconds = allSeconds - hours * 3600 - minutes * 60 || 0;
    if (seconds < 10 && seconds >= 0) {
      seconds = '0' + seconds;
    }
    return hours + ':' + minutes + ':' + seconds;
  }

  // we need to sync props with state values
  useEffect(() => { setStart(isStart) }, [isStart]);
  useEffect(() => { setAllSeconds(sec) }, [sec]);

  useEffect(() => {
    if (allSeconds === 0) {
      setStart(false);
    }
  }, [allSeconds === 0]);

  useEffect(() => {
    if (start) {
      const timerId = setInterval(() => { setAllSeconds(allSeconds => allSeconds - 1); console.log('tick') }, 1000);
      return () => clearInterval(timerId);
    }
  }, [start]);

  return (
    <div>
      <h2>Timer</h2>
      <h4>{getFullTime()}</h4>
    </div>
  )
}

const TimerControl = () => {
  const [hours, setHours] = useState(0);
  const [minutes, setMinutes] = useState(0);
  const [seconds, setSeconds] = useState(0);
  const [start, setStart] = useState(false);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', width: '200px' }}>
      <TimerWithControl sec={+hours * 3600 + +minutes * 60 + +seconds} isStart={start} />
      <span>Set hours</span>
      <input type='number' value={hours} onChange={e => setHours(e.target.value)} />
      <span>Set minutes</span>
      <input type='number' value={minutes} onChange={e => setMinutes(e.target.value)} />
      <span>Set seconds</span>
      <input type='number' value={seconds} onChange={e => setSeconds(e.target.value)} />
      <button onClick={() => setStart(start => !start)}>{!start ? 'Start' : 'Pause'}</button>
    </div>
  )
}

// TimerContainer
// SecondsTimer в данном случае играет роль presentation компонента, который сам ничего не умеет делать, а просто
// является шаблоном для отображения своих props в удобном для пользователя виде.
// Реализуйте контейнерный компонент, который будет обеспечивать состояние и логику для любого таймера:
// TimerContainer должен:
// воспринимать три пропса:
// seconds - секунды для обратного отсчета
// refresh - периодичность обновления таймера в миллисекундах
// render - компонент для отрисовки, которому передается текущее время
// Время вычисляется не по количеству обновлений, а по разности между стартовым и текущим моментом. Иначе
// таймер будет очень неточен так как JSX понимает переменные с маленькой буквы не как компоненты-функции, 
// а как тэги HTML, переприсвойте props render в переменную с большой буквы и используйте её в JSX,
// как имя компонента, передавая пропс seconds.
const SecondsTimer = ({ sec }) => <h2>{sec}</h2>

const TimerContainer = ({ seconds, refresh, render }) => {
  const [allSeconds, setAllSeconds] = useState(seconds);
  const [isRunning, setIsRunning] = useState(true);
  const Render = render;
  let startTime;

  // we need to sync props with state values
  useEffect(() => { setAllSeconds(seconds) }, [seconds]);

  useEffect(() => {
    startTime = Date.now();
    console.log('Start time:', startTime);
  }, []);

  useEffect(() => {
    if (allSeconds <= 0) {
      console.log('negative');
      setIsRunning(false);
      setAllSeconds(0);
    }
  }, [allSeconds <= 0]);

  useEffect(() => {
    if (isRunning) {
      startTime = Date.now();
      console.log('Start time:', startTime);
      const timerId = setInterval(() => setAllSeconds(allSeconds => Math.round(seconds - (Date.now() - startTime) / 1000)), refresh);

      return () => clearInterval(timerId);
    }
  }, [isRunning]);
  return (<Render sec={allSeconds} />);
}

// LCD
// Сделайте из компонента Timer presentation компонент без state, прикрутите его к TimerContainer
const TimerPresentation = ({ sec }) => {

  const getFullTime = () => {
    let hours = Math.floor(sec / 3600) || 0;
    if (hours < 10 && hours >= 0) {
      hours = '0' + hours;
    }
    let minutes = Math.floor((sec - hours * 3600) / 60) || 0;
    if (minutes < 10 && minutes >= 0) {
      minutes = '0' + minutes;
    }
    let seconds = sec - hours * 3600 - minutes * 60 || 0;
    if (seconds < 10 && seconds >= 0) {
      seconds = '0' + seconds;
    }
    return hours + ':' + minutes + ':' + seconds;
  }

  return (
    <div>
      <h2>Timer</h2>
      <h4>{getFullTime()}</h4>
    </div>
  )
}

// Watch
// Реализуйте часы со стрелками в качестве presentation компонента:
// квадратный блок-контейнер
// стрелки и, возможно, цифры позиционируются с помощью transform: rotate(УГОЛdeg)
// В верстке используйте position absolute для накладывания блоков стрелок и цифр друг на друга (это даст общий центр вращения)
// для корректного центра вращения блок со стрелкой или цифрой должен быть шириной с родительский квадратный блок
// есть еще всякий css (text-orientation) для вращения цифр внутри повернутого блока
const Watch = ({ sec }) => {
  let hours = Math.floor(sec / 3600) || 0;
  let minutes = Math.floor((sec % 3600) / 60) || 0;
  let seconds = sec % 3600 % 60 || 0;

  return (
    <div className='container'>
      <img src='images/ClockFace.png' className='clock' alt='' />
      <img src='images/ClockFace_H.png' className='arrow' style={{ transform: `rotate(${(hours % 12 + minutes / 60) * 30}deg)` }} alt='' />
      <img src='images/ClockFace_M.png' className='arrow' style={{ transform: `rotate(${(minutes + seconds / 60) * 6}deg)` }} alt='' />
      <img src='images/ClockFace_S.png' className='arrow' style={{ transform: `rotate(${seconds * 6}deg)` }} alt='' />
    </div>
  )
}

// TimerControl + TimerContainer
// Используя TimerControl обновите его код, в котором будет использоваться не Timer, а новый контейнерный компонент
const TimerControlPlusTimerContainer = () => {
  const [hours, setHours] = useState(0);
  const [minutes, setMinutes] = useState(0);
  const [seconds, setSeconds] = useState(0);
  const [start, setStart] = useState(false);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', width: '200px' }}>
      {start && <TimerContainer seconds={+hours * 3600 + +minutes * 60 + +seconds} refresh={100} render={TimerPresentation} />}
      <span>Set hours</span>
      <input type='number' value={hours} onChange={e => setHours(e.target.value)} />
      <span>Set minutes</span>
      <input type='number' value={minutes} onChange={e => setMinutes(e.target.value)} />
      <span>Set seconds</span>
      <input type='number' value={seconds} onChange={e => setSeconds(e.target.value)} />
      <button onClick={() => setStart(start => !start)}>{!start ? 'Start' : 'End'}</button>
    </div>
  )
}

function App() {
  return (
    <div className="App">
      <Spoiler header={<h1>Заголовок</h1>} open >
        Контент 1
        <p>
          лорем ипсум траливали и тп.
        </p>
      </Spoiler>
      <Spoiler>
        <h2>Контент 2</h2>
        <p>
          лорем ипсум траливали и тп.
        </p>
      </Spoiler>
      <RangeInput min={2} max={10} />
      <LoginForm onLogin={({ login, password }) => console.log('ЛОГИН И ПАРОЛЬ', login, password)} />
      <PasswordConfirm min={2} />
      <Timer sec={5} />
      <TimerControl />
      <TimerContainer seconds={1000} refresh={100} render={SecondsTimer} />
      <TimerContainer seconds={3600} refresh={100} render={TimerPresentation} />
      <TimerContainer seconds={3600} refresh={1000} render={Watch} />
      <TimerControlPlusTimerContainer />
    </div>
  );
}

export default App;
