/* ============================================================
   EATME PORTÁL – NEWS SERVICE

   Role:
   - EMPLOYEE: čte ALL + EMPLOYEE
   - MANAGER: čte ALL + MANAGER, může spravovat aktuality
   - ACCOUNTANT: čte ALL + ACCOUNTANT
   - ADMIN: čte všechny aktuality, může je spravovat

   Využívá existující:
   - NEWS
   - NEWS_READS
============================================================ */


/* ============================================================
   SETUP
============================================================ */

function setupNews() {

  ensureNewsSheet_(
    CFG.SHEETS.NEWS,
    HEADERS.NEWS
  );


  ensureNewsSheet_(
    CFG.SHEETS.NEWS_READS,
    HEADERS.NEWS_READS
  );


  Logger.log(
    'News setup OK'
  );

}



/* ============================================================
   AKTUALITY PRO PŘIHLÁŠENÉHO UŽIVATELE
============================================================ */

function getMyNews(token) {

  const user =
    requireUser_(
      token
    );


  const role =
    String(
      user.role ||
      ''
    ).toUpperCase();


  const now =
    new Date();


  const newsRows =
    rows_(
      CFG.SHEETS.NEWS
    );


  const readRows =
    rows_(
      CFG.SHEETS.NEWS_READS
    )
      .filter(
        function(row) {

          return (
            String(
              row.user_id
            ) ===
            String(
              user.user_id
            )
          );

        }
      );


  const readsByNews =
    {};


  readRows.forEach(
    function(row) {

      readsByNews[
        String(
          row.news_id
        )
      ] =
        row;

    }
  );


  return newsRows
    .filter(
      function(row) {

        if (
          !newsBool_(
            row.active
          )
        ) {

          return false;

        }


        const target =
          String(
            row.target_role ||
            'ALL'
          )
            .trim()
            .toUpperCase();


        /*
         * ADMIN vidí všechno.
         * Ostatní role pouze ALL + svou roli.
         */

        if (
          role !==
            'ADMIN' &&
          target !==
            'ALL' &&
          target !==
            role
        ) {

          return false;

        }


        const from =
          newsDate_(
            row.published_from
          );


        const to =
          newsDate_(
            row.published_to
          );


        if (
          from &&
          from.getTime() >
            now.getTime()
        ) {

          return false;

        }


        if (
          to &&
          to.getTime() <
            now.getTime()
        ) {

          return false;

        }


        return true;

      }
    )
    .map(
      function(row) {

        const read =
          readsByNews[
            String(
              row.news_id
            )
          ] ||
          null;


        return {

          news_id:
            String(
              row.news_id ||
              ''
            ),

          title:
            String(
              row.title ||
              ''
            ),

          content:
            String(
              row.content ||
              ''
            ),

          category:
            String(
              row.category ||
              ''
            ),

          target_role:
            String(
              row.target_role ||
              'ALL'
            ),

          published_from:
            row.published_from ||
            '',

          published_to:
            row.published_to ||
            '',

          require_confirmation:
            newsBool_(
              row.require_confirmation
            ),

          read_at:
            read
              ? read.read_at ||
                ''
              : '',

          confirmed_at:
            read
              ? read.confirmed_at ||
                ''
              : '',

          created_at:
            row.created_at ||
            ''

        };

      }
    )
    .sort(
      function(a,b) {

        const aImportant =
          String(
            a.category
          ).toUpperCase() ===
          'DŮLEŽITÉ'
            ? 1
            : 0;


        const bImportant =
          String(
            b.category
          ).toUpperCase() ===
          'DŮLEŽITÉ'
            ? 1
            : 0;


        if (
          aImportant !==
          bImportant
        ) {

          return (
            bImportant -
            aImportant
          );

        }


        return (
          newsTime_(
            b.created_at
          ) -
          newsTime_(
            a.created_at
          )
        );

      }
    );

}



/* ============================================================
   PŘEČTENO / POTVRZENO
============================================================ */

function markNewsRead(
  token,
  newsId,
  confirm
) {

  const user =
    requireUser_(
      token
    );


  const news =
    findOne_(
      CFG.SHEETS.NEWS,
      function(row) {

        return (
          String(
            row.news_id
          ) ===
          String(
            newsId
          )
        );

      }
    );


  if (
    !news
  ) {

    throw new Error(
      'Aktualita nebyla nalezena.'
    );

  }


  const existing =
    findOne_(
      CFG.SHEETS.NEWS_READS,
      function(row) {

        return (
          String(
            row.news_id
          ) ===
            String(
              newsId
            ) &&

          String(
            row.user_id
          ) ===
            String(
              user.user_id
            )
        );

      }
    );


  const stamp =
    now_();


  if (
    existing
  ) {

    const update =
      {};


    if (
      !existing.read_at
    ) {

      update.read_at =
        stamp;

    }


    if (
      confirm
    ) {

      update.confirmed_at =
        stamp;

    }


    if (
      Object.keys(
        update
      ).length
    ) {

      updateBy_(
        CFG.SHEETS.NEWS_READS,
        'news_read_id',
        existing.news_read_id,
        update
      );

    }

  } else {

    append_(
      CFG.SHEETS.NEWS_READS,
      {

        news_read_id:
          uuid_(
            'NR'
          ),

        news_id:
          newsId,

        user_id:
          user.user_id,

        read_at:
          stamp,

        confirmed_at:
          confirm
            ? stamp
            : ''

      }
    );

  }


  return {
    ok:true
  };

}


/* ============================================================
   HROMADNÉ OZNAČENÍ AKTUALIT JAKO PŘEČTENÉ

   Jeden request pro všechny zobrazené aktuality.
============================================================ */

function markNewsListRead(
  token,
  newsIds
) {

  const user =
    requireUser_(
      token
    );


  newsIds =
    Array.isArray(
      newsIds
    )
      ? newsIds
      : [];


  const uniqueIds =
    Array.from(
      new Set(
        newsIds
          .map(
            function(id) {

              return String(
                id ||
                ''
              ).trim();

            }
          )
          .filter(
            Boolean
          )
      )
    );


  if (
    !uniqueIds.length
  ) {

    return {
      ok:true
    };

  }


  const existingRows =
    rows_(
      CFG.SHEETS.NEWS_READS
    )
      .filter(
        function(row) {

          return (
            String(
              row.user_id
            ) ===
            String(
              user.user_id
            )
          );

        }
      );


  const existingByNews =
    {};


  existingRows.forEach(
    function(row) {

      existingByNews[
        String(
          row.news_id
        )
      ] =
        row;

    }
  );


  const stamp =
    now_();


  uniqueIds.forEach(
    function(newsId) {

      const existing =
        existingByNews[
          newsId
        ];


      if (
        existing
      ) {

        if (
          !existing.read_at
        ) {

          updateBy_(
            CFG.SHEETS.NEWS_READS,
            'news_read_id',
            existing.news_read_id,
            {
              read_at:
                stamp
            }
          );

        }

      } else {

        append_(
          CFG.SHEETS.NEWS_READS,
          {

            news_read_id:
              uuid_(
                'NR'
              ),

            news_id:
              newsId,

            user_id:
              user.user_id,

            read_at:
              stamp,

            confirmed_at:
              ''

          }
        );

      }

    }
  );


  return {
    ok:true
  };

}




/* ============================================================
   ADMIN / MANAGER – SEZNAM AKTUALIT
============================================================ */

function getAdminNews(token) {

  requireUser_(
    token,
    [
      'ADMIN',
      'MANAGER'
    ]
  );


  const newsRows =
    rows_(
      CFG.SHEETS.NEWS
    );


  const readRows =
    rows_(
      CFG.SHEETS.NEWS_READS
    );


  const users =
    rows_(
      CFG.SHEETS.USERS
    )
      .filter(
        function(user) {

          return newsBool_(
            user.active
          );

        }
      );


  return newsRows
    .map(
      function(row) {

        const newsId =
          String(
            row.news_id ||
            ''
          );


        const target =
          String(
            row.target_role ||
            'ALL'
          ).toUpperCase();


        const audience =
          users.filter(
            function(user) {

              return (
                target ===
                  'ALL' ||
                target ===
                  String(
                    user.role ||
                    ''
                  ).toUpperCase()
              );

            }
          );


        const reads =
          readRows.filter(
            function(read) {

              return (
                String(
                  read.news_id
                ) ===
                newsId
              );

            }
          );


        return {

          news_id:
            newsId,

          title:
            String(
              row.title ||
              ''
            ),

          content:
            String(
              row.content ||
              ''
            ),

          category:
            String(
              row.category ||
              ''
            ),

          target_role:
            String(
              row.target_role ||
              'ALL'
            ),

          published_from:
            row.published_from ||
            '',

          published_to:
            row.published_to ||
            '',

          require_confirmation:
            newsBool_(
              row.require_confirmation
            ),

          active:
            newsBool_(
              row.active
            ),

          created_at:
            row.created_at ||
            '',

          audience_count:
            audience.length,

          read_count:
            reads.filter(
              function(read) {

                return !!read.read_at;

              }
            ).length,

          confirmed_count:
            reads.filter(
              function(read) {

                return !!read.confirmed_at;

              }
            ).length

        };

      }
    )
    .sort(
      function(a,b) {

        return (
          newsTime_(
            b.created_at
          ) -
          newsTime_(
            a.created_at
          )
        );

      }
    );

}



/* ============================================================
   ADMIN / MANAGER – ULOŽIT AKTUALITU
============================================================ */

function saveAdminNews(
  token,
  payload
) {

  const user =
    requireUser_(
      token,
      [
        'ADMIN',
        'MANAGER'
      ]
    );


  payload =
    payload ||
    {};


  const title =
    String(
      payload.title ||
      ''
    ).trim();


  const content =
    String(
      payload.content ||
      ''
    ).trim();


  if (
    !title
  ) {

    throw new Error(
      'Vyplň nadpis aktuality.'
    );

  }


  if (
    !content
  ) {

    throw new Error(
      'Vyplň text aktuality.'
    );

  }


  const allowedTargets =
    [
      'ALL',
      'EMPLOYEE',
      'MANAGER',
      'ACCOUNTANT',
      'ADMIN'
    ];


  const targetRole =
    String(
      payload.target_role ||
      'ALL'
    ).toUpperCase();


  if (
    !allowedTargets.includes(
      targetRole
    )
  ) {

    throw new Error(
      'Neplatná cílová role.'
    );

  }


  const newsId =
    String(
      payload.news_id ||
      ''
    ).trim();


  const data =
    {

      title:
        title,

      content:
        content,

      category:
        String(
          payload.category ||
          'Provoz'
        ),

      company_id:
        String(
          payload.company_id ||
          ''
        ),

      location_id:
        String(
          payload.location_id ||
          ''
        ),

      target_role:
        targetRole,

      published_from:
        payload.published_from ||
        now_(),

      published_to:
        payload.published_to ||
        '',

      require_confirmation:
        !!payload.require_confirmation,

      active:
        payload.active !==
        false

    };


  if (
    newsId
  ) {

    const old =
      findOne_(
        CFG.SHEETS.NEWS,
        function(row) {

          return (
            String(
              row.news_id
            ) ===
            newsId
          );

        }
      );


    if (
      !old
    ) {

      throw new Error(
        'Aktualita nebyla nalezena.'
      );

    }


    updateBy_(
      CFG.SHEETS.NEWS,
      'news_id',
      newsId,
      data
    );


    audit_(
      user.user_id,
      'NEWS_UPDATED',
      'NEWS',
      newsId,
      old,
      data
    );


    return {
      ok:true,
      news_id:newsId
    };

  }


  const newId =
    uuid_(
      'NEWS'
    );


  append_(
    CFG.SHEETS.NEWS,
    {

      news_id:
        newId,

      title:
        data.title,

      content:
        data.content,

      category:
        data.category,

      company_id:
        data.company_id,

      location_id:
        data.location_id,

      target_role:
        data.target_role,

      published_from:
        data.published_from,

      published_to:
        data.published_to,

      require_confirmation:
        data.require_confirmation,

      active:
        data.active,

      created_by:
        user.user_id,

      created_at:
        now_()

    }
  );


  audit_(
    user.user_id,
    'NEWS_CREATED',
    'NEWS',
    newId,
    '',
    data
  );


  return {
    ok:true,
    news_id:newId
  };

}



/* ============================================================
   SKRÝT / ZOBRAZIT
============================================================ */

function setAdminNewsActive(
  token,
  newsId,
  active
) {

  const user =
    requireUser_(
      token,
      [
        'ADMIN',
        'MANAGER'
      ]
    );


  const news =
    findOne_(
      CFG.SHEETS.NEWS,
      function(row) {

        return (
          String(
            row.news_id
          ) ===
          String(
            newsId
          )
        );

      }
    );


  if (
    !news
  ) {

    throw new Error(
      'Aktualita nebyla nalezena.'
    );

  }


  updateBy_(
    CFG.SHEETS.NEWS,
    'news_id',
    newsId,
    {
      active:
        !!active
    }
  );


  audit_(
    user.user_id,
    active
      ? 'NEWS_SHOWN'
      : 'NEWS_HIDDEN',
    'NEWS',
    newsId,
    news.active,
    !!active
  );


  return {
    ok:true
  };

}



/* ============================================================
   ADMIN – KDO PŘEČETL / POTVRDIL
============================================================ */

function getAdminNewsReaders(
  token,
  newsId
) {

  requireUser_(
    token,
    [
      'ADMIN',
      'MANAGER'
    ]
  );


  const news =
    findOne_(
      CFG.SHEETS.NEWS,
      function(row) {

        return (
          String(
            row.news_id
          ) ===
          String(
            newsId
          )
        );

      }
    );


  if (
    !news
  ) {

    throw new Error(
      'Aktualita nebyla nalezena.'
    );

  }


  const target =
    String(
      news.target_role ||
      'ALL'
    ).toUpperCase();


  const users =
    rows_(
      CFG.SHEETS.USERS
    )
      .filter(
        function(user) {

          if (
            !newsBool_(
              user.active
            )
          ) {

            return false;

          }


          return (
            target ===
              'ALL' ||
            target ===
              String(
                user.role ||
                ''
              ).toUpperCase()
          );

        }
      );


  const employees =
    rows_(
      CFG.SHEETS.EMPLOYEES
    );


  const reads =
    rows_(
      CFG.SHEETS.NEWS_READS
    )
      .filter(
        function(row) {

          return (
            String(
              row.news_id
            ) ===
            String(
              newsId
            )
          );

        }
      );


  return users
    .map(
      function(user) {

        const read =
          reads.find(
            function(row) {

              return (
                String(
                  row.user_id
                ) ===
                String(
                  user.user_id
                )
              );

            }
          ) ||
          null;


        const employee =
          employees.find(
            function(row) {

              return (
                String(
                  row.employee_id
                ) ===
                String(
                  user.employee_id ||
                  ''
                )
              );

            }
          ) ||
          null;


        return {

          user_id:
            String(
              user.user_id ||
              ''
            ),

          name:
            employee
              ? (
                  String(
                    employee.first_name ||
                    ''
                  ) +
                  ' ' +
                  String(
                    employee.last_name ||
                    ''
                  )
                ).trim()
              : String(
                  user.email ||
                  ''
                ),

          email:
            String(
              user.email ||
              ''
            ),

          role:
            String(
              user.role ||
              ''
            ),

          read_at:
            read
              ? read.read_at ||
                ''
              : '',

          confirmed_at:
            read
              ? read.confirmed_at ||
                ''
              : ''

        };

      }
    );

}



/* ============================================================
   HELPERS
============================================================ */

function newsBool_(value) {

  return (
    value ===
      true ||
    String(
      value
    ).toUpperCase() ===
      'TRUE' ||
    String(
      value
    ) ===
      '1'
  );

}


function newsDate_(value) {

  if (
    !value
  ) {

    return null;

  }


  const date =
    value instanceof Date
      ? value
      : new Date(
          value
        );


  return isNaN(
    date.getTime()
  )
    ? null
    : date;

}


function newsTime_(value) {

  const date =
    newsDate_(
      value
    );


  return date
    ? date.getTime()
    : 0;

}


function ensureNewsSheet_(
  sheetName,
  headers
) {

  try {

    const existing =
      sh_(
        sheetName
      );


    if (
      existing
    ) {

      return existing;

    }

  }

  catch(error) {

    /*
     * List ještě neexistuje.
     */

  }


  let spreadsheet =
    null;


  try {

    spreadsheet =
      sh_(
        CFG.SHEETS.USERS
      ).getParent();

  }

  catch(error) {

    /*
     * Fallback níže.
     */

  }


  if (
    !spreadsheet
  ) {

    spreadsheet =
      SpreadsheetApp
        .getActiveSpreadsheet();

  }


  if (
    !spreadsheet
  ) {

    throw new Error(
      'Nepodařilo se otevřít databázový spreadsheet.'
    );

  }


  let sheet =
    spreadsheet.getSheetByName(
      sheetName
    );


  if (
    !sheet
  ) {

    sheet =
      spreadsheet.insertSheet(
        sheetName
      );


    sheet
      .getRange(
        1,
        1,
        1,
        headers.length
      )
      .setValues(
        [
          headers
        ]
      );


    sheet.setFrozenRows(
      1
    );

  }


  return sheet;

}
