<template>
	<div class="ui basic segment no-fluf-segment">
		
		<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">

			<div class="sixteen wide column">
				<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
				
				<div class="ui grid">

					<div class="six wide column" v-if="!$store.getters.getIsUserOnMobile">
						<search-input></search-input>
					</div>
					
					<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">

						<div class="ui basic button" 
						v-on:click="updateFastFilters(3)" 
						v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)" 
						style="position: relative;">
							<i class="green mail icon"></i>Shared Notes
							<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
								{{ $store.getters.totals['unreadNotes'] }}
							</span>
						</div>

						<div class="ui basic button" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
							<i class="green archive icon"></i>Archived
							<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
						</div>

						<div class="ui basic button" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['encryptedNotes'] > 0">
							<i class="green lock alternate icon"></i>Locked
							<!-- <span>{{ $store.getters.totals['encryptedNotes'] }}</span> -->
						</div>
						
					</div>

					<div class="eight wide column" v-if="showClear">
						<!-- <fast-filters /> -->
						<span class="ui fluid green button" 
							
							@click="reset">
							<i class="arrow circle left icon"></i>Back to All Notes
						</span>
					</div>

				</div>

			</div>

<!-- 			<div class="one wide column"></div>
				<div class="fourteen wide column">
					<input-notes :noteid="3153" :position="3" ref="note3" />
				</div>
			<div class="one wide column"></div> -->

			<h2 v-if="fastFilters['withLinks'] == 1">Notes with Links</h2>
			<h2 v-if="fastFilters['withTags'] == 1">Notes with Tags</h2>
			<h2 v-if="fastFilters['onlyArchived'] == 1">Archived Notes</h2>
			<h2 v-if="fastFilters['onlyShowSharedNotes'] == 1">Shared Notes</h2>
			<h2 v-if="fastFilters['onlyShowEncrypted'] == 1">Password Protected Notes</h2>

			<!-- tags section  -->
			<div v-if="commonTags.length > 0" class="sixteen wide column">
				<h4><i class="green tags icon"></i>Tags</h4>
				<span v-for="tag in commonTags" @click="toggleTagFilter(tag.id)">
					<span class="ui clickable basic label" :class="{ 'green':(searchTags.includes(tag.id)) }">
					{{ucWords(tag.text)}} <span class="detail">{{tag.usages}}</span>
					</span>
				</span>
			</div>

			<!-- Note title card display  -->
			<div class="sixteen wide column">

				<h3 v-if="$store.getters.totals && $store.getters.totals['totalNotes'] == 0">
					No Notes Yet. Thats ok. Create one when you feel ready.
				</h3>

				<!-- Go to one wide column, do not do this on mobile interface -->
				<div :class="{'one-column':( 
						(activeNoteId1 != null || activeNoteId2 != null) &&
						!$store.getters.getIsUserOnMobile
					)}">

					<!-- render each section based on notes in set  -->
					<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
						<h4><i :class="`green ${sectionData[index][0]} icon`"></i>{{ sectionData[index][1] }}</h4>

						<div class="note-card-display-area">
							<note-title-display-card 
								v-for="note in section"
								:onClick="openNote"
								:data="note"
								:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
								:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
							/>
						</div>
					</div>

				</div>
			</div>


			<!-- found attachments  -->
			<div class="sixteen wide column" v-if="foundAttachments.length > 0">
				<h4><i class="folder open outline icon"></i> Found in Files ({{ foundAttachments.length }})</h4>
				<attachment-display 
					v-for="item in foundAttachments" 
					:item="item"
					:key="item.id"
					:search-params="{}"
				/>
			</div>

		</div>

		
		<input-notes v-if="activeNoteId1 != null" :noteid="activeNoteId1" :position="activeNote1Position" ref="note1" />
		<input-notes v-if="activeNoteId2 != null" :noteid="activeNoteId2" :position="activeNote2Position" ref="note2" />

	</div>
</template>

<script>
	
	import axios from 'axios'

	export default {
	name: 'SearchBar',
		components: {
			'input-notes': require('@/components/NoteInputPanel.vue').default,
			'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
			'fast-filters': require('@/components/FastFilters.vue').default,
			'search-input': require('@/components/SearchInput.vue').default,
			'attachment-display': require('@/components/AttachmentDisplayCard').default,
			'counter':require('@/components/AnimatedCounterComponent.vue').default
		},
		data () {
			return {
				initComponent: true,
				commonTags: [],
				searchTerm: '',
				searchTags: [],
				notes: [],
				highlights: [],
				searchDebounce: null,
				fastFilters: {},
				working: false,
				//Load up notes in batches
				firstLoadBatchSize: 30, //First set of rapidly loaded notes
				batchSize: 100, //Size of batch loaded when user scrolls through current batch
				batchOffset: 0, //Tracks the current batch that has been loaded
				loadingBatchTimeout: null, //Limit how quickly batches can be loaded
				loadingInProgress: false,
				fetchTags: false,

				//Clear button is not visible 
				showClear: false,
				initialPostData: null,
				currentPostData: null,

				containsNormalNotes: 0,
				containsPinnednotes: 0,
				containsTextResults: 0,
				// containsTagResults: 0,
				// containsAttachmentResults: 0,

				//Currently open notes in app
				activeNoteId1: null,
				activeNoteId2: null,

				//Position determines how note is Positioned
				activeNote1Position: 0,
				activeNote2Position: 0,

				lastVisibilityState: null,

				foundAttachments: [],

				sectionData: {
					'pinned': 		['thumbtack', 'Pinned'],
					'archived': 	['archive', 'Archived'],
					'shared': 		['envelope outline', 'Received Notes'],
					'sent': 		['paper plane outline', 'Shared Notes'],
					'notes': 		['file','Notes'],
					'highlights': 	['paragraph', 'Found In Text'],
					'locked': 		['lock', 'Password Protected']
				},
				noteSections: {
					pinned: [],
					archived: [],
					shared:[],
					sent:[],
					notes: [],
					highlights: [],
					locked: []
				},

			}
		},
		beforeMount(){

			this.$parent.loginGateway()

			//Update totals for app
			this.$store.dispatch('fetchAndUpdateUserTotals')

			this.$bus.$on('close_active_note', ({position, noteId, modified}) => {
				this.closeNote(position)
				this.$store.dispatch('fetchAndUpdateUserTotals')
				if(modified){
					this.updateSingleNote(noteId)
				}
			})

			this.$bus.$on('update_single_note', (noteId) => {
				this.updateSingleNote(noteId)
			})

			this.$bus.$on('note_deleted', (noteId) => {
				//Remove deleted note from set, its deleted
				this.fetchUserTags()
				Object.keys(this.noteSections).forEach( key => {
					this.noteSections[key].forEach( (note, index) => {
						if(note.id == noteId){
							this.noteSections[key].splice(index,1)
							return
						}
					})
				})
				
			})
			this.$bus.$on('update_fast_filters', newFilter => {
				this.fastFilters = newFilter
				//Fast filters always return all the results and tags
				this.search(true, this.batchSize, false).then( () => {
					return this.fetchUserTags()
				})
			})

			//Event to update search from other areas
			this.$bus.$on('update_search_term', sentInSearchTerm => {
				this.searchTerm = sentInSearchTerm
				this.search(true, this.batchSize)
					.then( () => {

						this.searchAttachments()

						return this.fetchUserTags()
					})
			})

			//New note button pushes open note event
			this.$bus.$on('open_note', noteId => {
				this.openNote(noteId)
			})

			//Reload page content
			this.$bus.$on('note_reload', () => {
				this.reset()
			})

			//Mount notes on load if note ID is set
			if(this.$route.params && this.$route.params.id){
				const id = this.$route.params.id
				this.openNote(id)
			}
			window.addEventListener('scroll', this.onScroll)

			//Close notes when back button is pressed
			window.addEventListener('hashchange', this.hashChangeAction)

			//update note on visibility change
			document.addEventListener('visibilitychange', this.visibiltyChangeAction);

		},
		beforeDestroy(){
			window.removeEventListener('scroll', this.onScroll)
			window.removeEventListener('hashchange', this.hashChangeAction)
			document.removeEventListener('visibilitychange', this.visibiltyChangeAction)

			//We want to remove event listeners, but something here is messing them up and preventing ALL event listeners from working
			// this.$off() // Remove all event listeners
			// this.$bus.$off()
		},
		mounted() {

			//Loads initial batch and tags
			this.reset()
		},
		methods: {
			showOneColumn(){
				//If note 1 or 2 is open, show one column. Or if the user is on mobile
				return (this.activeNoteId1 != null || this.activeNoteId2 != null) &&
						!this.$store.getters.getIsUserOnMobile
			},
			openNote(id, event = null){

				//Don't open note if a link is clicked in display card
				if(event && event.target && event.target.nodeName){
					const nodeClick = event.target.nodeName
					if(nodeClick == 'A'){ return }	
				}

				//Do not open same note twice
				if(this.activeNoteId1 == id || this.activeNoteId2 == id){
					return;
				}

				//1 note open
				if(this.activeNoteId1 == null && this.activeNoteId2 == null){
					this.activeNoteId1 = id
					this.activeNote1Position = 0 //Middel of page
					this.$router.push('/notes/open/'+this.activeNoteId1)
					return
				}
				//2 notes open
				if(this.activeNoteId1 != null && this.activeNoteId2 == null){
					this.activeNoteId2 = id
					this.activeNote1Position = 1 //Right side of page
					this.activeNote2Position = 2 //Left side of page
					return
				}
				//2 notes open
				if(this.activeNoteId2 != null && this.activeNoteId1 == null){
					this.activeNoteId1 = id
					this.activeNote1Position = 2 //Right side of page
					this.activeNote2Position = 1 //Left side of page
					return
				}
			},
			closeNote(position){
				//One note open, close that note
				if(position == 0){
					this.activeNoteId1 = null
					this.activeNoteId2 = null
				}
				//Right note closed, thats 1
				if(position == 1){
					this.activeNoteId1 = null
				}
				if(position == 2){
					this.activeNoteId2 = null
				}

				//IF two notes get opened, update ID of open note
				if(this.activeNoteId1 || this.activeNoteId2){
					this.$router.push('/notes/open/'+Math.max(this.activeNoteId1,this.activeNoteId2))
				} else {
					//No notes are open, just show notes page
					this.$router.push('/notes')
				}

				this.activeNote1Position = 0
				this.activeNote2Position = 0

			},
			toggleTagFilter(tagId){

				if(this.searchTags.includes(tagId)){
					this.searchTags.splice( this.searchTags.indexOf(tagId) , 1);
				} else {
					this.searchTags.push(tagId)
				}

				//Reset note set and load up notes and tags
				if(this.searchTags.length > 0){
					this.search(true, this.batchSize)
					return
				}

				//If no tags are selected, reset entire page
				this.reset()

			},
			onScroll(e){

				clearTimeout(this.loadingBatchTimeout)
				this.loadingBatchTimeout = setTimeout(() => {

					//Distance to bottom of page
					const bottomOfWindow = 
					Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) 
					+ window.innerHeight

					//height of page
					const offsetHeight = this.$refs.content.clientHeight

					//Determine percentage down the page
					const percentageDown = Math.round( (bottomOfWindow/offsetHeight)*100 )

					//If greater than 80 of the way down the page, load the next batch
					if(percentageDown >= 80){
						
						this.search(false, this.batchSize, true)
					}

				}, 50)

				
				return
			},
			//Try to close notes on URL hash change /notes/open/123 to /notes - parse 123, close note id 123
			hashChangeAction(event){

				//Clean up path of hash change
				let path = window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.hash
				let newPath = event.newURL.replace(path,'')
				let oldPath = event.oldURL.replace(path,'')

				//If we go from open note ID to no note ID, close the note
				if(newPath == '' && oldPath.indexOf('/open/') != -1){
					//Pull note ID out of URL
					const noteIdToClose = oldPath.split('/').pop()
						
					if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
						this.$refs.note1.close()
					}

					if(this.$refs.note2 && this.$refs.note2.currentNoteId == noteIdToClose){
						this.$refs.note2.close()
					}	
				}
			},
			visibiltyChangeAction(event){

				//@TODO - set a timeout on this like 2 minutes or just dont do shit and update it via socket.io
				//If user leaves page then returns to page, reload the first batch
				if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
					//Load initial batch, then tags, then other batch
					this.search(false, this.firstLoadBatchSize)
					.then( () => {
						return this.fetchUserTags()
					})
				}

				this.lastVisibilityState = document.visibilityState

			},
			// @TODO Don't even trigger this if the note wasn't changed
			updateSingleNote(noteId){

				//Lookup one note using passed in ID
				const postData = {
					searchQuery: this.searchTerm,
					searchTags: this.searchTags,
					fastFilters:{
						noteIdSet:[noteId]
					}
				}

				axios.post('/api/note/search', postData)
				.then(results => {

					//Pull note data out of note set
					let newNote = results.data.notes[0]
					let foundNote = false

					if(newNote === undefined){
						return
					}

					//Find Just updated note and modify all its attributes
					Object.keys(this.noteSections).forEach(key => {

						this.noteSections[key].forEach( (note,index) => {

							if(note.id == noteId){
								foundNote = true

								//Don't move notes that were not changed
								if(note.updated == newNote.updated){
									// return
								}

								//Compare note tags, if they changed, reload tags
								if(newNote.tag_count != note.tag_count){
									this.fetchUserTags()
								}

								//go through each prop and update it with new values
								Object.keys(newNote).forEach(prop => {
									note[prop] = newNote[prop]
								})

								//Remove note from location and push to front
								this.noteSections[key].splice(index, 1)
								this.noteSections[key].unshift(note)

								return
							}
						})
					})

					//New notes don't exist in list, push them to the front
					if(!foundNote){
						this.noteSections.notes.unshift(newNote)
					}
					//Trigger section rebuild
					this.rebuildNoteCategorise()
				})
			},
			searchAttachments(){
				axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
				.then(results => {
					this.foundAttachments = results.data
				})
			},
			search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
				return new Promise((resolve, reject) => {

					//Don't double load note batches
					if(this.loadingInProgress){
						return resolve()
					}

					//Reset a lot of stuff if we are not merging batches
					if(!mergeExisting){
						this.batchOffset = 0 // Reset batch offset if we are not merging note batches
						// this.commonTags = [] //Don't reset tags, if search returns tags, they will be set
					}

					//Remove all filter limits from previous queries
					delete this.fastFilters.limitSize
					delete this.fastFilters.limitOffset

					let postData = {
						searchQuery: this.searchTerm,
						searchTags: this.searchTags,
						fastFilters: this.fastFilters,
					}

					//Save initial post data on first load
					if(this.initialPostData == null){
						this.initialPostData = JSON.stringify(postData)
					}
					//If post data is not the same as initial, show clear button
					if(JSON.stringify(postData) != this.initialPostData){
						this.showClear = true
					}

					if(notesInNextLoad && notesInNextLoad > 0){
						//Create limit based off of the number of notes already loaded
						postData.fastFilters.limitSize = notesInNextLoad
						postData.fastFilters.limitOffset = this.batchOffset
					}

					//Perform search - or die
					this.loadingInProgress = true
					axios.post('/api/note/search', postData)
					.then(response => {

						//Save the number of notes just loaded
						this.batchOffset += response.data.notes.length

						//Mush the two new sets of data together (set will be empty is reset is on)
						if(response.data.tags.length > 0){
							this.commonTags = response.data.tags
						}
						
						this.loadingInProgress = false
						this.generateNoteCategories(response.data.notes, mergeExisting)

						return resolve(true)
					})
				})
			},
			rebuildNoteCategorise(){
				let currentNotes = []
				Object.keys(this.noteSections).forEach( key => {
					this.noteSections[key].forEach( note => {
						currentNotes.push(note)
					})
				})
				this.generateNoteCategories(currentNotes, false)
			},
			generateNoteCategories(notes, mergeExisting){
				// Place each note in a category based on certain attributes and fast filters

				//Reset all sections if we are not merging existing
				if(!mergeExisting){
					Object.keys(this.noteSections).forEach( key => {
						this.noteSections[key] = []
					})
				}

				//Sort notes into defined sections
				notes.forEach(note => {

					if(note.archived == 1 && this.fastFilters.onlyArchived == 1){
						this.noteSections.archived.push(note)
						return
					}
					if(note.shareUsername != null){
						this.noteSections.shared.push(note)
						return
					}
					//Only show sent notes section if shared is selected
					if(note.shared == 2 && this.fastFilters.onlyShowSharedNotes == 1){
						this.noteSections.sent.push(note)
						return
					}
					if(note.encrypted == 1 && this.fastFilters.onlyShowEncrypted == 1){
						this.noteSections.locked.push(note)
						return
					}
					if(note.note_highlights.length > 0){
						this.noteSections.highlights.push(note)
						return
					}
					// Pinned notes are always first, they can appear in the archive
					if(note.pinned == 1){
						this.noteSections.pinned.push(note)
						return
					}

					this.noteSections.notes.push(note)
				})

			},
			searchKeyUp(){
				let vm = this
				clearTimeout(vm.searchDebounce)
				vm.searchDebounce = setTimeout(() => {
					this.search(true, this.batchSize)
					.then( () => {
						return this.fetchUserTags()
					})
				}, 500)
			},
			ucWords(str){
				return (str + '')
				.replace(/^(.)|\s+(.)/g, function ($1) {
					return $1.toUpperCase()
				})
			},
			reset(){
				this.showClear = false
				this.searchTerm = ''
				this.searchTags = []
				this.fastFilters = {}
				this.foundAttachments = [] //Remove all attachments 
				this.$bus.$emit('reset_fast_filters')

				//Load initial batch, then tags, then other batch
				this.search(true, this.firstLoadBatchSize)
				.then( () => {
					return this.fetchUserTags()
				})
				.then( () => {
					//Load a larger batch once first batch has loaded
					return this.search(false, this.batchSize, true)
				})
				.then( i => { 
					//Thats how you promise chain
				})
			},
			fetchUserTags(){
				return new Promise((resolve, reject) => {

					let postData = {
						searchQuery: this.searchTerm,
						searchTags: this.searchTags,
						fastFilters: this.fastFilters,
					}

					axios.post('/api/tag/usertags', postData)
					.then( ({data}) => {
						this.commonTags = data
						resolve(data)
					})
				})
			},
			updateFastFilters(index){

				//clear out tags
				this.searchTags = []

				//A little hacky, brings user to notes page then filters on click
				if(this.$route.name != 'NotesPage'){
					this.$router.push('/notes')
					setTimeout( () => {
						this.updateFastFilters(index)
					}, 500 )
				}

				const options = [
					'withLinks', // 'Only Show Notes with Links'
					'withTags', // 'Only Show Notes with Tags'
					'onlyArchived', //'Only Show Archived Notes'
					'onlyShowSharedNotes', //Only show shared notes
					'onlyShowEncrypted',
				]

				let filter = {}
				filter[options[index]] = 1

				this.$bus.$emit('update_fast_filters', filter)
			}
		}
	}
</script>
<style type="text/css" scoped>
	.mush-it-up {
		width: calc(50% - 130px);
	}
	.detail {
		float: right;
	}
	.note-card-display-area {
		display: flex;
		flex-wrap: wrap;
	}
	.display-area-title {
		width: 100%;
		display: inline-block;
	}
	.note-card-section {
		/*padding-bottom: 15px;*/
	}
	.note-card-section + .note-card-section {
		padding: 15px 0 0;
	}
</style>