text: // @flow
  
  import type {LinkInfo} from '../../components/forms/LinkInfo.jsx'
  import type {FileInfo} from '../common/FileInfo.jsx'
  import {PositionInfo} from "../forms/PositionInfo.jsx";
  import {LocationInfo, getLocationDisplayString} from "../common/location/LocationInfo.js";
  import type {MyGroupData} from "../stores/MyGroupsStore.js";
  import type {GroupTileAPIData} from "./GroupAPIUtils.js";
  import type {EventTileAPIData} from "./EventAPIUtils.js";
  import _ from 'lodash';
  
  export type APIResponse = {|
    +status: number
  |};
  
  export type APIError = {|
    +errorCode: number,
    +errorMessage: string
  |};
  
  export type TagDefinition = {|
    id: number,
    tag_name: string,
    display_name: string,
    caption: string,
    category: string,
    subcategory: string,
    parent: string
  |};
  
  export type TagDefinitionCount = {|
    num_times: number
  |} & TagDefinition;
  
  export type ProjectData = {|
    +id: number,
    +ownerId: number,
    +description: string,
    +issueArea: $ReadOnlyArray<TagDefinition>,
    +stage: $ReadOnlyArray<TagDefinition>,
    +location: string,
    +country: string,
    +state: string,
    +city: string,
    +name: string,
    +thumbnail: FileInfo,
    +claimed: boolean,
    +date_modified: string
  |};
  
  export type ProjectAPIData = {|
    +project_id: number,
    +project_creator: number,
    +project_description: string,
    +project_issue_area: $ReadOnlyArray<TagDefinition>,
    +project_stage: $ReadOnlyArray<TagDefinition>,
    +project_location: string,
    +project_country: string,
    +project_state: string,
    +project_city: string,
    +project_name: string,
    +project_thumbnail: FileInfo,
    +project_date_modified: string,
    +project_url: string,
    +project_positions: $ReadOnlyArray<PositionInfo>
  |};
  
  export type VolunteerUserData = {|
    +id: number,
    +first_name: string,
    +last_name: string,
    +user_thumbnail: FileInfo,
    +about_me: string
  |}
  
  export type VolunteerDetailsAPIData = {|
    +application_id: number,
    +user: VolunteerUserData,
    +application_text: string,
    +application_date: string,
    +platform_date_joined: string,
    +roleTag: TagDefinition,
    +isApproved: boolean,
    +isCoOwner: boolean,
    +isUpForRenewal: boolean
  |}
  
  export type ProjectDetailsAPIData = {|
    +project_id: number,
    +project_description: string,
    +project_description_solution: string,
    +project_description_actions: string,
    +project_short_description: string,
    +project_creator: number,
    +project_claimed: boolean,
    +project_approved: boolean,
    +project_url: string,
    +project_organization: $ReadOnlyArray<TagDefinition>,
    +project_organization_type: $ReadOnlyArray<TagDefinition>,
    +project_issue_area: $ReadOnlyArray<TagDefinition>,
    +project_stage: $ReadOnlyArray<TagDefinition>,
    +project_technologies: $ReadOnlyArray<TagDefinition>,
    +project_positions: $ReadOnlyArray<PositionInfo>,
    +project_groups: $ReadOnlyArray<MyGroupData>,
    +project_location: string,
    +project_country: string,
    +project_state: string,
    +project_city: string,
    +project_name: string,
    +project_thumbnail: FileInfo,
    +project_links: $ReadOnlyArray<LinkInfo>,
    +project_files: $ReadOnlyArray<FileInfo>,
    +project_owners: $ReadOnlyArray<VolunteerUserData>,
    +project_volunteers: $ReadOnlyArray<VolunteerDetailsAPIData>,
    +project_date_modified: Date,
    +project_groups: $ReadOnlyArray<GroupTileAPIData>,
    +project_events: $ReadOnlyArray<EventTileAPIData>
  |};
  
  export type TeamAPIData = {|
    +board_of_directors: string,
    +project: ProjectDetailsAPIData
  |}
  
  class ProjectAPIUtils {
    static projectFromAPIData(apiData: ProjectAPIData): ProjectData {
      return {
        description: apiData.project_description,
        id: apiData.project_id,
        issueArea:
          apiData.project_issue_area && apiData.project_issue_area.length != 0
            ? apiData.project_issue_area[0].display_name
            : 'None',
        stage:
          apiData.project_stage && apiData.project_stage.length !=0
            ? apiData.project_stage[0].display_name
            : 'None',
        project_organization_type:
          apiData.project_organization_type && apiData.project_organization_type.length != 0
            ? apiData.project_organization_type[0].display_name
            : 'None',
        location: apiData.project_location,
        country: apiData.project_country,
        state: apiData.project_state,
        city: apiData.project_city,
        name: apiData.project_name,
        thumbnail: apiData.project_thumbnail,
        ownerId: apiData.project_creator,
        claimed: apiData.project_claimed,
        date_modified: apiData.project_date_modified,
        url: apiData.project_url,
        positions: !_.isEmpty(apiData.project_positions)
            ? ProjectAPIUtils.getSkillNames(apiData.project_positions)
            : ['Contact Project for Details'],
      };
    }
    
    static getLocationDisplayName(project: ProjectAPIData | ProjectDetailsAPIData | ProjectData): string {
      // TODO: See if we can deprecate ProjectData
      const location: LocationInfo = {
        location_id: project.project_location || project.location,
        city: project.project_city || project.city,
        state: project.project_state || project.state,
        country: project.project_country || project.country
      };
      return getLocationDisplayString(location);
    }
  
    static getSkillNames(positions: array) {
      return positions.map(function(data) {
        return data.roleTag.display_name
      });
    }
  
    static fetchProjectDetails(id: number, callback: (ProjectDetailsAPIData) => void, errCallback: (APIError) => void): void {
      fetch(new Request('/api/project/' + id + '/', {credentials: 'include'}))
        .then(response => {
          if(!response.ok) {
            throw Error();
          }
          return response.json();
        })
        .then(projectDetails => {
          callback(projectDetails);
          // TODO: Get catch to return http status code
        }).catch(response => errCallback && errCallback({
          errorCode: response.status,
          errorMessage: JSON.stringify(response)
        }));
    }
    // fetch specific category of tags
    static fetchTagsByCategory(tagCategory: string, getCounts: boolean, callback: ($ReadOnlyArray<TagDefinition>) => void, errCallback: (APIError) => void): Promise<$ReadOnlyArray<TagDefinition>> {
      return fetch(new Request('/api/tags?category=' + tagCategory + '&getCounts=' + getCounts || 'false')) //default to false if call doesn't pass a getCounts arg
        .then(response => response.json())
        .then(tags => callback(tags))
        .catch(response => errCallback && errCallback({
          errorCode: response.status,
          errorMessage: JSON.stringify(response)
        }));
    }
    // fetch all tags in one API request
    static fetchAllTags(getCounts: boolean, callback: ($ReadOnlyArray<TagDefinition>) => void, errCallback: (APIError) => void): Promise<$ReadOnlyArray<TagDefinition>> {
      return fetch(new Request('/api/tags?getCounts=' + getCounts || 'false'))
        .then(response => response.json())
        .then(tags => callback(tags))
        .catch(response => errCallback && errCallback({
          errorCode: response.status,
          errorMessage: JSON.stringify(response)
        }));
    }
    //fetch DemocracyLab board information
    static fetchTeamDetails(callback: (TeamAPIData) => void): void {
      fetch('/api/team')
      .then(response => {
        return response.json()
      })
      .then(data => {
        callback(data);
      })
      .catch(err => {
        console.log('Error fetching team details. Error: ' + err)
      })
    }
  
    static post(url: string, body: {||},successCallback: (APIResponse) => void, errCallback: (APIError) => void) {
      const doError = (response) => errCallback && errCallback({
        errorCode: response.status,
        errorMessage: JSON.stringify(response)
      });
  
      fetch(new Request(url, {method:"POST", body:JSON.stringify(body), credentials:"include", headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
      },}))
        .then(response => ProjectAPIUtils.isSuccessResponse(response) ? successCallback() : doError(response))
        .catch(response => doError(response));
    }
  
    static isSuccessResponse(response:APIResponse): boolean {
      return response.status < 400;
    }
  }
  
  export default ProjectAPIUtils
  